From 0ff5189fb5eea29d6ddefe969961bfb1ab7c3aa4 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 20 Nov 2025 16:15:30 -0500 Subject: [PATCH 1/3] [tool] Remove code analysis from podspec-check Replaces the full build-and-analyze version of `pod lib lint` with the `--quick` version. This means that this step no longer does native code analysis (which `analyze` covers), so it no longer needs an exclusion list for packages with warnings. As a result of this change, flutter/packages no longer has a dependency on the version of Flutter that was published to CocoaPods to facilitate podspec testing. Fixes https://github.com/flutter/flutter/issues/178806 --- .ci/targets/macos_repo_checks.yaml | 2 +- .../tool/lib/src/podspec_check_command.dart | 31 +++------ .../tool/test/podspec_check_command_test.dart | 63 +------------------ 3 files changed, 11 insertions(+), 85 deletions(-) diff --git a/.ci/targets/macos_repo_checks.yaml b/.ci/targets/macos_repo_checks.yaml index 95fa5774f69e..8a349dec1c7d 100644 --- a/.ci/targets/macos_repo_checks.yaml +++ b/.ci/targets/macos_repo_checks.yaml @@ -13,5 +13,5 @@ tasks: always: true - name: validate iOS and macOS podspecs script: .ci/scripts/tool_runner.sh - args: ["podspec-check", "--exclude=script/configs/exclude_xcode_deprecation.yaml"] + args: ["podspec-check"] always: true diff --git a/script/tool/lib/src/podspec_check_command.dart b/script/tool/lib/src/podspec_check_command.dart index 7cbb31087883..c126792743b4 100644 --- a/script/tool/lib/src/podspec_check_command.dart +++ b/script/tool/lib/src/podspec_check_command.dart @@ -36,7 +36,7 @@ class PodspecCheckCommand extends PackageLoopingCommand { @override final String description = - 'Runs "pod lib lint" on all iOS and macOS plugin podspecs, as well as ' + 'Runs "pod lib lint --quick" on all iOS and macOS plugin podspecs, as well as ' 'making sure the podspecs follow repository standards.\n\n' 'This command requires "pod" and "flutter" to be in your path. Runs on macOS only.'; @@ -111,11 +111,6 @@ class PodspecCheckCommand extends PackageLoopingCommand { } Future> _podspecsToLint(RepositoryPackage package) async { - // Since the pigeon platform tests podspecs require generated files that are not included in git, - // the podspec lint fails. - if (package.path.contains('packages/pigeon/platform_tests/')) { - return []; - } final List podspecs = await getFilesForPackage(package).where((File entity) { final String filename = entity.basename; @@ -137,29 +132,19 @@ class PodspecCheckCommand extends PackageLoopingCommand { print('Linting $podspecBasename'); // Lint plugin as framework (use_frameworks!). - final ProcessResult frameworkResult = - await _runPodLint(podspecPath, libraryLint: true); - print(frameworkResult.stdout); - print(frameworkResult.stderr); - - // Lint plugin as library. - final ProcessResult libraryResult = - await _runPodLint(podspecPath, libraryLint: false); - print(libraryResult.stdout); - print(libraryResult.stderr); - - return frameworkResult.exitCode == 0 && libraryResult.exitCode == 0; + final ProcessResult lintResult = await _runPodLint(podspecPath); + print(lintResult.stdout); + print(lintResult.stderr); + + return lintResult.exitCode == 0; } - Future _runPodLint(String podspecPath, - {required bool libraryLint}) async { + Future _runPodLint(String podspecPath) async { final List arguments = [ 'lib', 'lint', podspecPath, - '--configuration=Debug', // Release targets unsupported arm64 simulators. Use Debug to only build against targeted x86_64 simulator devices. - '--skip-tests', - if (libraryLint) '--use-libraries' + '--quick', ]; print('Running "pod ${arguments.join(' ')}"'); diff --git a/script/tool/test/podspec_check_command_test.dart b/script/tool/test/podspec_check_command_test.dart index 0ba71840dd1e..0ff19b76aa83 100644 --- a/script/tool/test/podspec_check_command_test.dart +++ b/script/tool/test/podspec_check_command_test.dart @@ -153,22 +153,7 @@ void main() { .platformDirectory(FlutterPlatform.ios) .childFile('plugin1.podspec') .path, - '--configuration=Debug', - '--skip-tests', - '--use-libraries' - ], - packagesDir.path), - ProcessCall( - 'pod', - [ - 'lib', - 'lint', - plugin - .platformDirectory(FlutterPlatform.ios) - .childFile('plugin1.podspec') - .path, - '--configuration=Debug', - '--skip-tests', + '--quick', ], packagesDir.path), ]), @@ -207,22 +192,7 @@ void main() { .platformDirectory(FlutterPlatform.macos) .childFile('plugin1.podspec') .path, - '--configuration=Debug', - '--skip-tests', - '--use-libraries' - ], - packagesDir.path), - ProcessCall( - 'pod', - [ - 'lib', - 'lint', - plugin - .platformDirectory(FlutterPlatform.macos) - .childFile('plugin1.podspec') - .path, - '--configuration=Debug', - '--skip-tests', + '--quick', ], packagesDir.path), ]), @@ -283,35 +253,6 @@ void main() { )); }); - test('fails if linting as a static library fails', () async { - final RepositoryPackage plugin = createFakePlugin('plugin1', packagesDir); - _writeFakePodspec(plugin, 'ios'); - - // Simulate failure from the second call to `pod`. - processRunner.mockProcessesForExecutable['pod'] = [ - FakeProcessInfo(MockProcess()), - FakeProcessInfo(MockProcess(exitCode: 1)), - ]; - - Error? commandError; - final List output = await runCapturingPrint( - runner, ['podspec-check'], errorHandler: (Error e) { - commandError = e; - }); - - expect(commandError, isA()); - - expect( - output, - containsAllInOrder( - [ - contains('The following packages had errors:'), - contains('plugin1:\n' - ' plugin1.podspec') - ], - )); - }); - test('fails if an iOS Swift plugin is missing the search paths workaround', () async { final RepositoryPackage plugin = createFakePlugin( From 42ccb60d7b45254e6158391e01d825f68d52eb94 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 20 Nov 2025 16:25:27 -0500 Subject: [PATCH 2/3] Minor cleanup --- script/tool/lib/src/podspec_check_command.dart | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/script/tool/lib/src/podspec_check_command.dart b/script/tool/lib/src/podspec_check_command.dart index c126792743b4..e768a5168c50 100644 --- a/script/tool/lib/src/podspec_check_command.dart +++ b/script/tool/lib/src/podspec_check_command.dart @@ -125,14 +125,9 @@ class PodspecCheckCommand extends PackageLoopingCommand { } Future _lintPodspec(File podspec) async { - // Do not run the static analyzer on plugins with known analyzer issues. - final String podspecPath = podspec.path; + print('Linting ${podspec.basename}'); - final String podspecBasename = podspec.basename; - print('Linting $podspecBasename'); - - // Lint plugin as framework (use_frameworks!). - final ProcessResult lintResult = await _runPodLint(podspecPath); + final ProcessResult lintResult = await _runPodLint(podspec.path); print(lintResult.stdout); print(lintResult.stderr); From 2b970d431f3bf93f46895380bfe8c7496317fbe9 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 24 Nov 2025 18:36:41 -0500 Subject: [PATCH 3/3] Apply formatting from head --- analysis_options.yaml | 9 +- script/tool/lib/src/analyze_command.dart | 265 +- .../src/branch_for_batch_release_command.dart | 141 +- .../tool/lib/src/build_examples_command.dart | 205 +- script/tool/lib/src/common/cmake.dart | 24 +- script/tool/lib/src/common/file_utils.dart | 8 +- .../lib/src/common/flutter_command_utils.dart | 21 +- .../lib/src/common/git_version_finder.dart | 59 +- script/tool/lib/src/common/gradle.dart | 13 +- .../tool/lib/src/common/package_command.dart | 367 +-- .../src/common/package_looping_command.dart | 149 +- .../lib/src/common/package_state_utils.dart | 106 +- script/tool/lib/src/common/plugin_utils.dart | 60 +- .../tool/lib/src/common/process_runner.dart | 64 +- script/tool/lib/src/common/pub_utils.dart | 29 +- .../lib/src/common/pub_version_finder.dart | 41 +- .../lib/src/common/repository_package.dart | 32 +- script/tool/lib/src/common/xcode.dart | 113 +- .../src/create_all_packages_app_command.dart | 129 +- script/tool/lib/src/custom_test_command.dart | 34 +- script/tool/lib/src/dart_test_command.dart | 70 +- .../lib/src/dependabot_check_command.dart | 57 +- .../tool/lib/src/drive_examples_command.dart | 261 +- .../src/federation_safety_check_command.dart | 96 +- script/tool/lib/src/fetch_deps_command.dart | 152 +- .../lib/src/firebase_test_lab_command.dart | 183 +- script/tool/lib/src/fix_command.dart | 10 +- script/tool/lib/src/format_command.dart | 312 ++- script/tool/lib/src/gradle_check_command.dart | 476 ++-- .../tool/lib/src/license_check_command.dart | 107 +- script/tool/lib/src/list_command.dart | 8 +- script/tool/lib/src/main.dart | 80 +- .../lib/src/make_deps_path_based_command.dart | 180 +- script/tool/lib/src/native_test_command.dart | 362 +-- .../tool/lib/src/podspec_check_command.dart | 69 +- .../tool/lib/src/publish_check_command.dart | 136 +- script/tool/lib/src/publish_command.dart | 174 +- .../tool/lib/src/pubspec_check_command.dart | 214 +- script/tool/lib/src/readme_check_command.dart | 193 +- .../src/remove_dev_dependencies_command.dart | 18 +- .../src/repo_package_info_check_command.dart | 149 +- .../lib/src/update_dependency_command.dart | 286 ++- .../tool/lib/src/update_excerpts_command.dart | 128 +- .../tool/lib/src/update_min_sdk_command.dart | 47 +- .../lib/src/update_release_info_command.dart | 127 +- .../tool/lib/src/version_check_command.dart | 266 +- script/tool/pubspec.yaml | 2 +- script/tool/test/analyze_command_test.dart | 1807 +++++++------ ...branch_for_batch_release_command_test.dart | 500 ++-- .../test/build_examples_command_test.dart | 1051 ++++---- script/tool/test/common/file_utils_test.dart | 48 +- .../test/common/git_version_finder_test.dart | 81 +- script/tool/test/common/gradle_test.dart | 150 +- .../tool/test/common/output_utils_test.dart | 42 +- .../test/common/package_command_test.dart | 1979 ++++++++------ .../common/package_command_test.mocks.dart | 330 ++- .../common/package_looping_command_test.dart | 1083 ++++---- .../test/common/package_state_utils_test.dart | 529 ++-- .../tool/test/common/plugin_utils_test.dart | 357 ++- script/tool/test/common/pub_utils_test.dart | 89 +- .../test/common/pub_version_finder_test.dart | 29 +- .../test/common/repository_package_test.dart | 167 +- script/tool/test/common/xcode_test.dart | 341 ++- .../create_all_packages_app_command_test.dart | 439 ++-- .../tool/test/custom_test_command_test.dart | 365 +-- script/tool/test/dart_test_command_test.dart | 834 +++--- .../test/dependabot_check_command_test.dart | 173 +- .../test/drive_examples_command_test.dart | 1307 +++++----- .../federation_safety_check_command_test.dart | 508 ++-- script/tool/test/fetch_deps_command_test.dart | 811 +++--- .../test/firebase_test_lab_command_test.dart | 918 ++++--- script/tool/test/fix_command_test.dart | 36 +- script/tool/test/format_command_test.dart | 1061 ++++---- .../tool/test/gradle_check_command_test.dart | 1411 ++++++---- .../tool/test/license_check_command_test.dart | 631 +++-- script/tool/test/list_command_test.dart | 103 +- .../make_deps_path_based_command_test.dart | 795 +++--- script/tool/test/mocks.dart | 10 +- .../tool/test/native_test_command_test.dart | 2287 ++++++++++------- .../tool/test/podspec_check_command_test.dart | 622 ++--- .../tool/test/publish_check_command_test.dart | 723 +++--- script/tool/test/publish_command_test.dart | 1523 ++++++----- .../tool/test/pubspec_check_command_test.dart | 1540 ++++++----- .../tool/test/readme_check_command_test.dart | 528 ++-- .../remove_dev_dependencies_command_test.dart | 74 +- .../repo_package_info_check_command_test.dart | 463 ++-- .../test/update_dependency_command_test.dart | 1651 ++++++------ .../test/update_excerpts_command_test.dart | 234 +- .../test/update_min_sdk_command_test.dart | 88 +- .../update_release_info_command_test.dart | 621 +++-- script/tool/test/util.dart | 171 +- .../tool/test/version_check_command_test.dart | 1991 ++++++++------ 92 files changed, 21053 insertions(+), 15480 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index a5de895abc41..0d631cee7a2b 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -29,7 +29,7 @@ linter: - always_declare_return_types - always_put_control_body_on_new_line # - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219 - - always_specify_types + # - always_specify_types # conflicts with omit_obvious_local_variable_types # - always_use_package_imports # we do this commonly - annotate_overrides # - avoid_annotating_with_dynamic # conflicts with always_specify_types @@ -128,7 +128,8 @@ linter: - noop_primitive_operations - null_check_on_nullable_type_parameter - null_closures - # - omit_local_variable_types # opposite of always_specify_types + # - omit_local_variable_types # conflicts with specify_nonobvious_local_variable_types + - omit_obvious_local_variable_types # - one_member_abstracts # too many false positives - only_throw_errors # this does get disabled in a few places where we have legacy code that uses strings et al - overridden_fields @@ -187,10 +188,12 @@ linter: - sort_constructors_first - sort_pub_dependencies # DIFFERENT FROM FLUTTER/FLUTTER: Flutter's use case for not sorting does not apply to this repository. - sort_unnamed_constructors_first + - specify_nonobvious_local_variable_types + - specify_nonobvious_property_types - test_types_in_equals - throw_in_finally - tighten_type_of_initializing_formals - # - type_annotate_public_apis # subset of always_specify_types + - type_annotate_public_apis - type_init_formals - type_literal_in_constant_pattern - unawaited_futures # DIFFERENT FROM FLUTTER/FLUTTER: It's disabled there for "too many false positives"; that's not an issue here, and missing awaits have caused production issues in plugins. diff --git a/script/tool/lib/src/analyze_command.dart b/script/tool/lib/src/analyze_command.dart index b281c7b7a419..57fa2fefc3aa 100644 --- a/script/tool/lib/src/analyze_command.dart +++ b/script/tool/lib/src/analyze_command.dart @@ -28,47 +28,72 @@ class AnalyzeCommand extends PackageLoopingCommand { // Platform options. // By default, only Dart analysis is run. argParser.addFlag(_dartFlag, help: "Runs 'dart analyze'", defaultsTo: true); - argParser.addFlag(platformAndroid, - help: "Runs 'gradle lint' on Android code"); - argParser.addFlag(platformIOS, - help: "Runs 'xcodebuild analyze' on iOS code"); - argParser.addFlag(platformMacOS, - help: "Runs 'xcodebuild analyze' on macOS code"); + argParser.addFlag( + platformAndroid, + help: "Runs 'gradle lint' on Android code", + ); + argParser.addFlag( + platformIOS, + help: "Runs 'xcodebuild analyze' on iOS code", + ); + argParser.addFlag( + platformMacOS, + help: "Runs 'xcodebuild analyze' on macOS code", + ); // Dart options. - argParser.addMultiOption(_customAnalysisFlag, - help: - 'Directories (comma separated) that are allowed to have their own ' - 'analysis options.\n\n' - 'Alternately, a list of one or more YAML files that contain a list ' - 'of allowed directories.', - defaultsTo: []); - argParser.addOption(_analysisSdk, - valueHelp: 'dart-sdk', - help: 'An optional path to a Dart SDK; this is used to override the ' - 'SDK used to provide analysis.'); - argParser.addFlag(_downgradeFlag, - help: 'Runs "flutter pub downgrade" before analysis to verify that ' - 'the minimum constraints are sufficiently new for APIs used.'); - argParser.addFlag(_libOnlyFlag, - help: 'Only analyze the lib/ directory of the main package, not the ' - 'entire package.'); - argParser.addFlag(_skipIfResolvingFailsFlag, - help: 'If resolution fails, skip the package. This is only ' - 'intended to be used with pathified analysis, where a resolver ' - 'failure indicates that no out-of-band failure can result anyway.', - hide: true); + argParser.addMultiOption( + _customAnalysisFlag, + help: + 'Directories (comma separated) that are allowed to have their own ' + 'analysis options.\n\n' + 'Alternately, a list of one or more YAML files that contain a list ' + 'of allowed directories.', + defaultsTo: [], + ); + argParser.addOption( + _analysisSdk, + valueHelp: 'dart-sdk', + help: + 'An optional path to a Dart SDK; this is used to override the ' + 'SDK used to provide analysis.', + ); + argParser.addFlag( + _downgradeFlag, + help: + 'Runs "flutter pub downgrade" before analysis to verify that ' + 'the minimum constraints are sufficiently new for APIs used.', + ); + argParser.addFlag( + _libOnlyFlag, + help: + 'Only analyze the lib/ directory of the main package, not the ' + 'entire package.', + ); + argParser.addFlag( + _skipIfResolvingFailsFlag, + help: + 'If resolution fails, skip the package. This is only ' + 'intended to be used with pathified analysis, where a resolver ' + 'failure indicates that no out-of-band failure can result anyway.', + hide: true, + ); // Xcode options. - argParser.addOption(_minIOSVersionArg, - help: 'Sets the minimum iOS deployment version to use when compiling, ' - 'overriding the default minimum version. This can be used to find ' - 'deprecation warnings that will affect the plugin in the future.'); - argParser.addOption(_minMacOSVersionArg, - help: - 'Sets the minimum macOS deployment version to use when compiling, ' - 'overriding the default minimum version. This can be used to find ' - 'deprecation warnings that will affect the plugin in the future.'); + argParser.addOption( + _minIOSVersionArg, + help: + 'Sets the minimum iOS deployment version to use when compiling, ' + 'overriding the default minimum version. This can be used to find ' + 'deprecation warnings that will affect the plugin in the future.', + ); + argParser.addOption( + _minMacOSVersionArg, + help: + 'Sets the minimum macOS deployment version to use when compiling, ' + 'overriding the default minimum version. This can be used to find ' + 'deprecation warnings that will affect the plugin in the future.', + ); } static const String _dartFlag = 'dart'; @@ -88,33 +113,41 @@ class AnalyzeCommand extends PackageLoopingCommand { final String name = 'analyze'; @override - final String description = 'Analyzes all packages using dart analyze.\n\n' + final String description = + 'Analyzes all packages using dart analyze.\n\n' 'This command requires "dart" and "flutter" to be in your path.'; /// Checks that there are no unexpected analysis_options.yaml files. bool _hasUnexpectedAnalysisOptions(RepositoryPackage package) { - final List files = - package.directory.listSync(recursive: true, followLinks: false); - for (final FileSystemEntity file in files) { + final List files = package.directory.listSync( + recursive: true, + followLinks: false, + ); + for (final file in files) { if (file.basename != 'analysis_options.yaml' && file.basename != '.analysis_options') { continue; } final bool allowed = _allowedCustomAnalysisDirectories.any( - (String directory) => - directory.isNotEmpty && - path.isWithin( - packagesDir.childDirectory(directory).path, file.path)); + (String directory) => + directory.isNotEmpty && + path.isWithin( + packagesDir.childDirectory(directory).path, + file.path, + ), + ); if (allowed) { continue; } printError( - 'Found an extra analysis_options.yaml at ${file.absolute.path}.'); + 'Found an extra analysis_options.yaml at ${file.absolute.path}.', + ); printError( - 'If this was deliberate, pass the package to the analyze command ' - 'with the --$_customAnalysisFlag flag and try again.'); + 'If this was deliberate, pass the package to the analyze command ' + 'with the --$_customAnalysisFlag flag and try again.', + ); return true; } return false; @@ -155,14 +188,15 @@ class AnalyzeCommand extends PackageLoopingCommand { _allowedCustomAnalysisDirectories = getYamlListArg(_customAnalysisFlag); // Use the Dart SDK override if one was passed in. - final String? dartSdk = argResults![_analysisSdk] as String?; - _dartBinaryPath = - dartSdk == null ? 'dart' : path.join(dartSdk, 'bin', 'dart'); + final dartSdk = argResults![_analysisSdk] as String?; + _dartBinaryPath = dartSdk == null + ? 'dart' + : path.join(dartSdk, 'bin', 'dart'); } @override Future runForPackage(RepositoryPackage package) async { - final Map subResults = {}; + final subResults = {}; if (getBoolArg(_dartFlag)) { _printSectionHeading('Running dart analyze.'); subResults['Dart'] = await _runDartAnalysisForPackage(package); @@ -208,28 +242,32 @@ class AnalyzeCommand extends PackageLoopingCommand { return subResults.values.first; } // Otherwise, aggregate the messages, with the least positive status. - final Map failedResults = - Map.of(subResults) - ..removeWhere((String key, PackageResult value) => - value.state != RunState.failed); - final Map skippedResults = - Map.of(subResults) - ..removeWhere((String key, PackageResult value) => - value.state != RunState.skipped); + final failedResults = Map.of(subResults) + ..removeWhere( + (String key, PackageResult value) => value.state != RunState.failed, + ); + final skippedResults = Map.of(subResults) + ..removeWhere( + (String key, PackageResult value) => value.state != RunState.skipped, + ); // If anything failed, collect all the failure messages, prefixed by type. if (failedResults.isNotEmpty) { return PackageResult.fail([ for (final MapEntry entry in failedResults.entries) - '${entry.key}${entry.value.details.isEmpty ? '' : ': ${entry.value.details.join(', ')}'}' + '${entry.key}${entry.value.details.isEmpty ? '' : ': ${entry.value.details.join(', ')}'}', ]); } // If everything was skipped, mark as skipped with all of the explanations. if (skippedResults.length == subResults.length) { - return PackageResult.skip(skippedResults.entries - .map((MapEntry entry) => - '${entry.key}: ${entry.value.details.first}') - .join(', ')); + return PackageResult.skip( + skippedResults.entries + .map( + (MapEntry entry) => + '${entry.key}: ${entry.value.details.first}', + ) + .join(', '), + ); } // For all succes, or a mix of success and skip, log any skips but mark as // success. @@ -247,7 +285,8 @@ class AnalyzeCommand extends PackageLoopingCommand { /// Runs Dart analysis for the given package, and returns the result that /// applies to that analysis. Future _runDartAnalysisForPackage( - RepositoryPackage package) async { + RepositoryPackage package, + ) async { final bool libOnly = getBoolArg(_libOnlyFlag); if (libOnly && !package.libDirectory.existsSync()) { @@ -265,24 +304,26 @@ class AnalyzeCommand extends PackageLoopingCommand { // analyzing. `example` packages can be skipped since 'flutter pub get' // automatically runs `pub get` in examples as part of handling the parent // directory. - final List packagesToGet = [ + final packagesToGet = [ package, if (!libOnly) ...package.getSubpackages(), ]; - for (final RepositoryPackage packageToGet in packagesToGet) { + for (final packageToGet in packagesToGet) { if (packageToGet.directory.basename != 'example' || - !RepositoryPackage(packageToGet.directory.parent) - .pubspecFile - .existsSync()) { + !RepositoryPackage( + packageToGet.directory.parent, + ).pubspecFile.existsSync()) { if (!await _runPubCommand(packageToGet, 'get')) { if (getBoolArg(_skipIfResolvingFailsFlag)) { // Re-run, capturing output, to see if the failure was a resolver // failure. (This is slightly inefficient, but this should be a // very rare case.) - const String resolverFailureMessage = 'version solving failed'; + const resolverFailureMessage = 'version solving failed'; final io.ProcessResult result = await processRunner.run( - flutterCommand, ['pub', 'get'], - workingDir: packageToGet.directory); + flutterCommand, + ['pub', 'get'], + workingDir: packageToGet.directory, + ); if ((result.stderr as String).contains(resolverFailureMessage) || (result.stdout as String).contains(resolverFailureMessage)) { logWarning('Skipping package due to pub resolution failure.'); @@ -297,9 +338,11 @@ class AnalyzeCommand extends PackageLoopingCommand { if (_hasUnexpectedAnalysisOptions(package)) { return PackageResult.fail(['Unexpected local analysis options']); } - final int exitCode = await processRunner.runAndStream(_dartBinaryPath, - ['analyze', '--fatal-infos', if (libOnly) 'lib'], - workingDir: package.directory); + final int exitCode = await processRunner.runAndStream( + _dartBinaryPath, + ['analyze', '--fatal-infos', if (libOnly) 'lib'], + workingDir: package.directory, + ); if (exitCode != 0) { return PackageResult.fail(); } @@ -308,28 +351,42 @@ class AnalyzeCommand extends PackageLoopingCommand { Future _runPubCommand(RepositoryPackage package, String command) async { final int exitCode = await processRunner.runAndStream( - flutterCommand, ['pub', command], - workingDir: package.directory); + flutterCommand, + ['pub', command], + workingDir: package.directory, + ); return exitCode == 0; } /// Runs Gradle lint analysis for the given package, and returns the result /// that applies to that analysis. Future _runGradleLintForPackage( - RepositoryPackage package) async { - if (!pluginSupportsPlatform(platformAndroid, package, - requiredMode: PlatformSupport.inline)) { + RepositoryPackage package, + ) async { + if (!pluginSupportsPlatform( + platformAndroid, + package, + requiredMode: PlatformSupport.inline, + )) { return PackageResult.skip( - 'Package does not contain native Android plugin code'); + 'Package does not contain native Android plugin code', + ); } for (final RepositoryPackage example in package.getExamples()) { - final GradleProject project = GradleProject(example, - processRunner: processRunner, platform: platform); + final project = GradleProject( + example, + processRunner: processRunner, + platform: platform, + ); if (!project.isConfigured()) { final bool buildSuccess = await runConfigOnlyBuild( - example, processRunner, platform, FlutterPlatform.android); + example, + processRunner, + platform, + FlutterPlatform.android, + ); if (!buildSuccess) { printError('Unable to configure Gradle project.'); return PackageResult.fail(['Unable to configure Gradle.']); @@ -360,16 +417,21 @@ class AnalyzeCommand extends PackageLoopingCommand { FlutterPlatform targetPlatform, { List extraFlags = const [], }) async { - final String platformString = - targetPlatform == FlutterPlatform.ios ? 'iOS' : 'macOS'; - if (!pluginSupportsPlatform(targetPlatform.name, package, - requiredMode: PlatformSupport.inline)) { + final platformString = targetPlatform == FlutterPlatform.ios + ? 'iOS' + : 'macOS'; + if (!pluginSupportsPlatform( + targetPlatform.name, + package, + requiredMode: PlatformSupport.inline, + )) { return PackageResult.skip( - 'Package does not contain native $platformString plugin code'); + 'Package does not contain native $platformString plugin code', + ); } - final Xcode xcode = Xcode(processRunner: processRunner, log: true); - final List errors = []; + final xcode = Xcode(processRunner: processRunner, log: true); + final errors = []; for (final RepositoryPackage example in package.getExamples()) { // See https://github.com/flutter/flutter/issues/172427 for discussion of // why this is currently necessary. @@ -390,13 +452,16 @@ class AnalyzeCommand extends PackageLoopingCommand { if (!buildSuccess) { printError('Unable to prepare native project files.'); errors.add( - 'Unable to build ${getRelativePosixPath(example.directory, from: package.directory)}.'); + 'Unable to build ${getRelativePosixPath(example.directory, from: package.directory)}.', + ); continue; } // Running tests and static analyzer. - final String examplePath = getRelativePosixPath(example.directory, - from: package.directory.parent); + final String examplePath = getRelativePosixPath( + example.directory, + from: package.directory.parent, + ); print('Running $platformString tests and analyzer for $examplePath...'); final int exitCode = await xcode.runXcodeBuild( example.directory, @@ -408,17 +473,15 @@ class AnalyzeCommand extends PackageLoopingCommand { scheme: 'Runner', configuration: 'Debug', hostPlatform: platform, - extraFlags: [ - ...extraFlags, - 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', - ], + extraFlags: [...extraFlags, 'GCC_TREAT_WARNINGS_AS_ERRORS=YES'], ); if (exitCode == 0) { printSuccess('$examplePath ($platformString) passed analysis.'); } else { printError('$examplePath ($platformString) failed analysis.'); errors.add( - '${getRelativePosixPath(example.directory, from: package.directory)} failed analysis.'); + '${getRelativePosixPath(example.directory, from: package.directory)} failed analysis.', + ); } print('Removing Swift Package Manager override...'); diff --git a/script/tool/lib/src/branch_for_batch_release_command.dart b/script/tool/lib/src/branch_for_batch_release_command.dart index 68d7c5905c37..dad963f11116 100644 --- a/script/tool/lib/src/branch_for_batch_release_command.dart +++ b/script/tool/lib/src/branch_for_batch_release_command.dart @@ -69,26 +69,31 @@ class BranchForBatchReleaseCommand extends PackageCommand { final GitDir repository = await gitDir; print('Parsing package "${package.displayName}"...'); - final _PendingChangelogs pendingChangelogs = - await _getPendingChangelogs(package); + final _PendingChangelogs pendingChangelogs = await _getPendingChangelogs( + package, + ); if (pendingChangelogs.entries.isEmpty) { print('No pending changelogs found for ${package.displayName}.'); return; } - final Pubspec pubspec = - Pubspec.parse(package.pubspecFile.readAsStringSync()); + final pubspec = Pubspec.parse(package.pubspecFile.readAsStringSync()); if (pubspec.version == null || pubspec.version!.major < 1) { printError( - 'This script only supports packages with version >= 1.0.0. Current version: ${pubspec.version}.'); + 'This script only supports packages with version >= 1.0.0. Current version: ${pubspec.version}.', + ); throw ToolExit(_kExitPackageMalformed); } - final _ReleaseInfo releaseInfo = - _getReleaseInfo(pendingChangelogs.entries, pubspec.version!); + final _ReleaseInfo releaseInfo = _getReleaseInfo( + pendingChangelogs.entries, + pubspec.version!, + ); if (releaseInfo.newVersion == null) { - print('No version change specified in pending changelogs for ' - '${package.displayName}.'); + print( + 'No version change specified in pending changelogs for ' + '${package.displayName}.', + ); return; } @@ -109,24 +114,30 @@ class BranchForBatchReleaseCommand extends PackageCommand { /// /// Throws a [ToolExit] if the package does not have a pending_changelogs folder. Future<_PendingChangelogs> _getPendingChangelogs( - RepositoryPackage package) async { - final Directory pendingChangelogsDir = - package.directory.childDirectory('pending_changelogs'); + RepositoryPackage package, + ) async { + final Directory pendingChangelogsDir = package.directory.childDirectory( + 'pending_changelogs', + ); if (!pendingChangelogsDir.existsSync()) { printError( - 'No pending_changelogs folder found for ${package.displayName}.'); + 'No pending_changelogs folder found for ${package.displayName}.', + ); throw ToolExit(_kExitPackageMalformed); } final List pendingChangelogFiles = pendingChangelogsDir .listSync() .whereType() - .where((File f) => - f.basename.endsWith('.yaml') && f.basename != _kTemplateFileName) + .where( + (File f) => + f.basename.endsWith('.yaml') && f.basename != _kTemplateFileName, + ) .toList(); try { final List<_PendingChangelogEntry> entries = pendingChangelogFiles .map<_PendingChangelogEntry>( - (File f) => _PendingChangelogEntry.parse(f.readAsStringSync())) + (File f) => _PendingChangelogEntry.parse(f.readAsStringSync()), + ) .toList(); return _PendingChangelogs(entries, pendingChangelogFiles); } on FormatException catch (e) { @@ -140,11 +151,12 @@ class BranchForBatchReleaseCommand extends PackageCommand { /// This method read through the parsed changelog entries decide the new version /// by following the version change rules. See [_VersionChange] for more details. _ReleaseInfo _getReleaseInfo( - List<_PendingChangelogEntry> pendingChangelogEntries, - Version oldVersion) { - final List changelogs = []; + List<_PendingChangelogEntry> pendingChangelogEntries, + Version oldVersion, + ) { + final changelogs = []; int versionIndex = _VersionChange.skip.index; - for (final _PendingChangelogEntry entry in pendingChangelogEntries) { + for (final entry in pendingChangelogEntries) { changelogs.add(entry.changelog); versionIndex = math.min(versionIndex, entry.version.index); } @@ -154,10 +166,16 @@ class BranchForBatchReleaseCommand extends PackageCommand { final Version? newVersion = switch (effectiveVersionChange) { _VersionChange.skip => null, _VersionChange.major => Version(oldVersion.major + 1, 0, 0), - _VersionChange.minor => - Version(oldVersion.major, oldVersion.minor + 1, 0), - _VersionChange.patch => - Version(oldVersion.major, oldVersion.minor, oldVersion.patch + 1), + _VersionChange.minor => Version( + oldVersion.major, + oldVersion.minor + 1, + 0, + ), + _VersionChange.patch => Version( + oldVersion.major, + oldVersion.minor, + oldVersion.patch + 1, + ), }; return _ReleaseInfo(newVersion, changelogs); } @@ -177,11 +195,15 @@ class BranchForBatchReleaseCommand extends PackageCommand { required String remoteName, }) async { print(' Creating new branch "$branchName"...'); - final io.ProcessResult checkoutResult = - await git.runCommand(['checkout', '-b', branchName]); + final io.ProcessResult checkoutResult = await git.runCommand([ + 'checkout', + '-b', + branchName, + ]); if (checkoutResult.exitCode != 0) { printError( - 'Failed to create branch $branchName: ${checkoutResult.stderr}'); + 'Failed to create branch $branchName: ${checkoutResult.stderr}', + ); throw ToolExit(_kGitFailedToPush); } @@ -192,27 +214,29 @@ class BranchForBatchReleaseCommand extends PackageCommand { } void _updatePubspec(RepositoryPackage package, Version newVersion) { - final YamlEditor editablePubspec = - YamlEditor(package.pubspecFile.readAsStringSync()); + final editablePubspec = YamlEditor(package.pubspecFile.readAsStringSync()); editablePubspec.update(['version'], newVersion.toString()); package.pubspecFile.writeAsStringSync(editablePubspec.toString()); } void _updateChangelog(RepositoryPackage package, _ReleaseInfo releaseInfo) { - final String newHeader = '## ${releaseInfo.newVersion}'; + final newHeader = '## ${releaseInfo.newVersion}'; final List newEntries = releaseInfo.changelogs; String oldChangelogContent = package.changelogFile.readAsStringSync(); - final StringBuffer newChangelog = StringBuffer(); + final newChangelog = StringBuffer(); // If the changelog starts with ## NEXT, replace it with the new version // and append the new entries. - final RegExp nextSection = RegExp(r'^\s*## NEXT[ \t]*(\r?\n)*'); + final nextSection = RegExp(r'^\s*## NEXT[ \t]*(\r?\n)*'); final Match? match = nextSection.firstMatch(oldChangelogContent); if (match != null) { - final String replacement = '$newHeader\n\n${newEntries.join('\n')}\n'; - oldChangelogContent = - oldChangelogContent.replaceRange(match.start, match.end, replacement); + final replacement = '$newHeader\n\n${newEntries.join('\n')}\n'; + oldChangelogContent = oldChangelogContent.replaceRange( + match.start, + match.end, + replacement, + ); newChangelog.write(oldChangelogContent); } else { newChangelog.writeln(newHeader); @@ -225,19 +249,28 @@ class BranchForBatchReleaseCommand extends PackageCommand { package.changelogFile.writeAsStringSync(newChangelog.toString()); } - Future _stageAndCommitChanges(GitDir git, RepositoryPackage package, - List pendingChangelogFiles) async { - final List paths = - pendingChangelogFiles.map((File f) => f.path).toList(); - final io.ProcessResult rmResult = - await git.runCommand(['rm', ...paths]); + Future _stageAndCommitChanges( + GitDir git, + RepositoryPackage package, + List pendingChangelogFiles, + ) async { + final List paths = pendingChangelogFiles + .map((File f) => f.path) + .toList(); + final io.ProcessResult rmResult = await git.runCommand([ + 'rm', + ...paths, + ]); if (rmResult.exitCode != 0) { printError('Failed to rm ${paths.join(' ')}: ${rmResult.stderr}'); throw ToolExit(_kGitFailedToPush); } - final io.ProcessResult addResult = await git.runCommand( - ['add', package.pubspecFile.path, package.changelogFile.path]); + final io.ProcessResult addResult = await git.runCommand([ + 'add', + package.pubspecFile.path, + package.changelogFile.path, + ]); if (addResult.exitCode != 0) { printError('Failed to git add: ${addResult.stderr}'); throw ToolExit(_kGitFailedToPush); @@ -246,7 +279,7 @@ class BranchForBatchReleaseCommand extends PackageCommand { final io.ProcessResult commitResult = await git.runCommand([ 'commit', '-m', - '[${package.displayName}] Prepare for batch release' + '[${package.displayName}] Prepare for batch release', ]); if (commitResult.exitCode != 0) { printError('Failed to commit: ${commitResult.stderr}'); @@ -255,10 +288,16 @@ class BranchForBatchReleaseCommand extends PackageCommand { } Future _pushBranch( - GitDir git, String remoteName, String branchName) async { + GitDir git, + String remoteName, + String branchName, + ) async { print(' Pushing branch $branchName to remote $remoteName...'); - final io.ProcessResult pushResult = - await git.runCommand(['push', remoteName, branchName]); + final io.ProcessResult pushResult = await git.runCommand([ + 'push', + remoteName, + branchName, + ]); if (pushResult.exitCode != 0) { printError('Failed to push to $branchName: ${pushResult.stderr}'); throw ToolExit(_kGitFailedToPush); @@ -319,17 +358,19 @@ class _PendingChangelogEntry { final dynamic yaml = loadYaml(yamlContent); if (yaml is! YamlMap) { throw FormatException( - 'Expected a YAML map, but found ${yaml.runtimeType}.'); + 'Expected a YAML map, but found ${yaml.runtimeType}.', + ); } final dynamic changelogYaml = yaml['changelog']; if (changelogYaml is! String) { throw FormatException( - 'Expected "changelog" to be a string, but found ${changelogYaml.runtimeType}.'); + 'Expected "changelog" to be a string, but found ${changelogYaml.runtimeType}.', + ); } final String changelog = changelogYaml.trim(); - final String? versionString = yaml['version'] as String?; + final versionString = yaml['version'] as String?; if (versionString == null) { throw const FormatException('Missing "version" key.'); } diff --git a/script/tool/lib/src/build_examples_command.dart b/script/tool/lib/src/build_examples_command.dart index d38e27091641..c6136f49677b 100644 --- a/script/tool/lib/src/build_examples_command.dart +++ b/script/tool/lib/src/build_examples_command.dart @@ -19,7 +19,8 @@ const String _pluginToolsConfigFileName = '.pluginToolsConfig.yaml'; const String _pluginToolsConfigBuildFlagsKey = 'buildFlags'; const String _pluginToolsConfigGlobalKey = 'global'; -const String _pluginToolsConfigExample = ''' +const String _pluginToolsConfigExample = + ''' $_pluginToolsConfigBuildFlagsKey: $_pluginToolsConfigGlobalKey: - "--no-tree-shake-icons" @@ -56,8 +57,10 @@ class BuildExamplesCommand extends PackageLoopingCommand { argParser.addFlag(platformWeb); argParser.addFlag(platformWindows); argParser.addFlag(platformIOS); - argParser.addFlag(_platformFlagApk, - aliases: const [_flutterBuildTypeAndroidAlias]); + argParser.addFlag( + _platformFlagApk, + aliases: const [_flutterBuildTypeAndroidAlias], + ); argParser.addOption( kEnableExperiment, defaultsTo: '', @@ -70,38 +73,38 @@ class BuildExamplesCommand extends PackageLoopingCommand { // about it. static final Map _platforms = { - _platformFlagApk: const _PlatformDetails( - 'Android', - pluginPlatform: platformAndroid, - flutterBuildType: _flutterBuildTypeAndroid, - ), - platformIOS: const _PlatformDetails( - 'iOS', - pluginPlatform: platformIOS, - flutterBuildType: _flutterBuildTypeIOS, - extraBuildFlags: ['--no-codesign'], - ), - platformLinux: const _PlatformDetails( - 'Linux', - pluginPlatform: platformLinux, - flutterBuildType: _flutterBuildTypeLinux, - ), - platformMacOS: const _PlatformDetails( - 'macOS', - pluginPlatform: platformMacOS, - flutterBuildType: _flutterBuildTypeMacOS, - ), - platformWeb: const _PlatformDetails( - 'web', - pluginPlatform: platformWeb, - flutterBuildType: _flutterBuildTypeWeb, - ), - platformWindows: const _PlatformDetails( - 'Windows', - pluginPlatform: platformWindows, - flutterBuildType: _flutterBuildTypeWindows, - ), - }; + _platformFlagApk: const _PlatformDetails( + 'Android', + pluginPlatform: platformAndroid, + flutterBuildType: _flutterBuildTypeAndroid, + ), + platformIOS: const _PlatformDetails( + 'iOS', + pluginPlatform: platformIOS, + flutterBuildType: _flutterBuildTypeIOS, + extraBuildFlags: ['--no-codesign'], + ), + platformLinux: const _PlatformDetails( + 'Linux', + pluginPlatform: platformLinux, + flutterBuildType: _flutterBuildTypeLinux, + ), + platformMacOS: const _PlatformDetails( + 'macOS', + pluginPlatform: platformMacOS, + flutterBuildType: _flutterBuildTypeMacOS, + ), + platformWeb: const _PlatformDetails( + 'web', + pluginPlatform: platformWeb, + flutterBuildType: _flutterBuildTypeWeb, + ), + platformWindows: const _PlatformDetails( + 'Windows', + pluginPlatform: platformWindows, + flutterBuildType: _flutterBuildTypeWindows, + ), + }; @override final String name = 'build-examples'; @@ -140,29 +143,33 @@ class BuildExamplesCommand extends PackageLoopingCommand { platformFlags.sort(); if (!platformFlags.any((String platform) => getBoolArg(platform))) { printError( - 'None of ${platformFlags.map((String platform) => '--$platform').join(', ')} ' - 'were specified. At least one platform must be provided.'); + 'None of ${platformFlags.map((String platform) => '--$platform').join(', ')} ' + 'were specified. At least one platform must be provided.', + ); throw ToolExit(_exitNoPlatformFlags); } } @override Future runForPackage(RepositoryPackage package) async { - final List errors = []; + final errors = []; final bool isPlugin = isFlutterPlugin(package); final Iterable<_PlatformDetails> requestedPlatforms = _platforms.entries .where( - (MapEntry entry) => getBoolArg(entry.key)) + (MapEntry entry) => getBoolArg(entry.key), + ) .map((MapEntry entry) => entry.value); // Platform support is checked at the package level for plugins; there is // no package-level platform information for non-plugin packages. final Set<_PlatformDetails> buildPlatforms = isPlugin ? requestedPlatforms - .where((_PlatformDetails platform) => - pluginSupportsPlatform(platform.pluginPlatform, package)) - .toSet() + .where( + (_PlatformDetails platform) => + pluginSupportsPlatform(platform.pluginPlatform, package), + ) + .toSet() : requestedPlatforms.toSet(); String platformDisplayList(Iterable<_PlatformDetails> platforms) { @@ -170,49 +177,60 @@ class BuildExamplesCommand extends PackageLoopingCommand { } if (buildPlatforms.isEmpty) { - final String unsupported = requestedPlatforms.length == 1 + final unsupported = requestedPlatforms.length == 1 ? '${requestedPlatforms.first.label} is not supported' : 'None of [${platformDisplayList(requestedPlatforms)}] are supported'; return PackageResult.skip('$unsupported by this plugin'); } print('Building for: ${platformDisplayList(buildPlatforms)}'); - final Set<_PlatformDetails> unsupportedPlatforms = - requestedPlatforms.toSet().difference(buildPlatforms); + final Set<_PlatformDetails> unsupportedPlatforms = requestedPlatforms + .toSet() + .difference(buildPlatforms); if (unsupportedPlatforms.isNotEmpty) { final List skippedPlatforms = unsupportedPlatforms .map((_PlatformDetails platform) => platform.label) .toList(); skippedPlatforms.sort(); - print('Skipping unsupported platform(s): ' - '${skippedPlatforms.join(', ')}'); + print( + 'Skipping unsupported platform(s): ' + '${skippedPlatforms.join(', ')}', + ); } print(''); - final bool? swiftPackageManagerOverride = - isPlugin ? _swiftPackageManagerFeatureConfig : null; + final bool? swiftPackageManagerOverride = isPlugin + ? _swiftPackageManagerFeatureConfig + : null; - bool builtSomething = false; + var builtSomething = false; for (final RepositoryPackage example in package.getExamples()) { // Rather than changing global config state, enable SwiftPM via a // temporary package-level override. if (swiftPackageManagerOverride != null) { - print('Overriding enable-swift-package-manager to ' - '$swiftPackageManagerOverride'); - setSwiftPackageManagerState(example, - enabled: swiftPackageManagerOverride); + print( + 'Overriding enable-swift-package-manager to ' + '$swiftPackageManagerOverride', + ); + setSwiftPackageManagerState( + example, + enabled: swiftPackageManagerOverride, + ); } - final String packageName = - getRelativePosixPath(example.directory, from: packagesDir); + final String packageName = getRelativePosixPath( + example.directory, + from: packagesDir, + ); - for (final _PlatformDetails platform in buildPlatforms) { + for (final platform in buildPlatforms) { // Repo policy is that a plugin must have examples configured for all // supported platforms. For packages, just log and skip any requested // platform that a package doesn't have set up. if (!isPlugin && !example.appSupportsPlatform( - getPlatformByName(platform.pluginPlatform))) { + getPlatformByName(platform.pluginPlatform), + )) { print('Skipping ${platform.label} for $packageName; not supported.'); continue; } @@ -224,8 +242,11 @@ class BuildExamplesCommand extends PackageLoopingCommand { buildPlatform += ' (${platform.flutterBuildType})'; } print('\nBUILDING $packageName for $buildPlatform'); - if (!await _buildExample(example, platform.flutterBuildType, - extraBuildFlags: platform.extraBuildFlags)) { + if (!await _buildExample( + example, + platform.flutterBuildType, + extraBuildFlags: platform.extraBuildFlags, + )) { errors.add('$packageName (${platform.label})'); } } @@ -242,7 +263,8 @@ class BuildExamplesCommand extends PackageLoopingCommand { errors.add('No examples found'); } else { return PackageResult.skip( - 'No examples found supporting requested platform(s).'); + 'No examples found supporting requested platform(s).', + ); } } @@ -252,20 +274,26 @@ class BuildExamplesCommand extends PackageLoopingCommand { } Iterable _readExtraBuildFlagsConfiguration( - Directory directory) sync* { - final File pluginToolsConfig = - directory.childFile(_pluginToolsConfigFileName); + Directory directory, + ) sync* { + final File pluginToolsConfig = directory.childFile( + _pluginToolsConfigFileName, + ); if (pluginToolsConfig.existsSync()) { - final Object? configuration = - loadYaml(pluginToolsConfig.readAsStringSync()); + final Object? configuration = loadYaml( + pluginToolsConfig.readAsStringSync(), + ); if (configuration is! YamlMap) { printError('The $_pluginToolsConfigFileName file must be a YAML map.'); printError( - 'Currently, the key "$_pluginToolsConfigBuildFlagsKey" is the only one that has an effect.'); + 'Currently, the key "$_pluginToolsConfigBuildFlagsKey" is the only one that has an effect.', + ); printError( - 'It must itself be a map. Currently, in that map only the key "$_pluginToolsConfigGlobalKey"'); + 'It must itself be a map. Currently, in that map only the key "$_pluginToolsConfigGlobalKey"', + ); printError( - 'has any effect; it must contain a list of arguments to pass to the'); + 'has any effect; it must contain a list of arguments to pass to the', + ); printError('flutter tool.'); printError(_pluginToolsConfigExample); throw ToolExit(_exitInvalidPluginToolsConfig); @@ -275,11 +303,14 @@ class BuildExamplesCommand extends PackageLoopingCommand { configuration[_pluginToolsConfigBuildFlagsKey]; if (buildFlagsConfiguration is! YamlMap) { printError( - 'The $_pluginToolsConfigFileName file\'s "$_pluginToolsConfigBuildFlagsKey" key must be a map.'); + 'The $_pluginToolsConfigFileName file\'s "$_pluginToolsConfigBuildFlagsKey" key must be a map.', + ); printError( - 'Currently, in that map only the key "$_pluginToolsConfigGlobalKey" has any effect; it must '); + 'Currently, in that map only the key "$_pluginToolsConfigGlobalKey" has any effect; it must ', + ); printError( - 'contain a list of arguments to pass to the flutter tool.'); + 'contain a list of arguments to pass to the flutter tool.', + ); printError(_pluginToolsConfigExample); throw ToolExit(_exitInvalidPluginToolsConfig); } @@ -288,12 +319,15 @@ class BuildExamplesCommand extends PackageLoopingCommand { buildFlagsConfiguration[_pluginToolsConfigGlobalKey]; if (globalBuildFlagsConfiguration is! YamlList) { printError( - 'The $_pluginToolsConfigFileName file\'s "$_pluginToolsConfigBuildFlagsKey" key must be a map'); + 'The $_pluginToolsConfigFileName file\'s "$_pluginToolsConfigBuildFlagsKey" key must be a map', + ); printError('whose "$_pluginToolsConfigGlobalKey" key is a list.'); printError( - 'That list must contain a list of arguments to pass to the flutter tool.'); + 'That list must contain a list of arguments to pass to the flutter tool.', + ); printError( - 'For example, the $_pluginToolsConfigFileName file could look like:'); + 'For example, the $_pluginToolsConfigFileName file could look like:', + ); printError(_pluginToolsConfigExample); throw ToolExit(_exitInvalidPluginToolsConfig); } @@ -310,18 +344,15 @@ class BuildExamplesCommand extends PackageLoopingCommand { }) async { final String enableExperiment = getStringArg(kEnableExperiment); - final int exitCode = await processRunner.runAndStream( - flutterCommand, - [ - 'build', - flutterBuildType, - ...extraBuildFlags, - ..._readExtraBuildFlagsConfiguration(example.directory), - if (enableExperiment.isNotEmpty) - '--enable-experiment=$enableExperiment', - ], - workingDir: example.directory, - ); + final int exitCode = await processRunner + .runAndStream(flutterCommand, [ + 'build', + flutterBuildType, + ...extraBuildFlags, + ..._readExtraBuildFlagsConfiguration(example.directory), + if (enableExperiment.isNotEmpty) + '--enable-experiment=$enableExperiment', + ], workingDir: example.directory); return exitCode == 0; } } diff --git a/script/tool/lib/src/common/cmake.dart b/script/tool/lib/src/common/cmake.dart index ff369beb585f..841d3f25be23 100644 --- a/script/tool/lib/src/common/cmake.dart +++ b/script/tool/lib/src/common/cmake.dart @@ -50,8 +50,9 @@ class CMakeProject { /// The project's 'example' build directory for this instance's platform. Directory get buildDirectory { - Directory buildDir = - flutterProject.childDirectory('build').childDirectory(_platformDirName); + Directory buildDir = flutterProject + .childDirectory('build') + .childDirectory(_platformDirName); if (arch != null) { buildDir = buildDir.childDirectory(arch!); } @@ -109,16 +110,13 @@ class CMakeProject { String target, { List arguments = const [], }) { - return processRunner.runAndStream( - getCmakeCommand(), - [ - '--build', - buildDirectory.path, - '--target', - target, - if (platform.isWindows) ...['--config', buildMode], - ...arguments, - ], - ); + return processRunner.runAndStream(getCmakeCommand(), [ + '--build', + buildDirectory.path, + '--target', + target, + if (platform.isWindows) ...['--config', buildMode], + ...arguments, + ]); } } diff --git a/script/tool/lib/src/common/file_utils.dart b/script/tool/lib/src/common/file_utils.dart index 8d48796ce0c6..199e62196ab3 100644 --- a/script/tool/lib/src/common/file_utils.dart +++ b/script/tool/lib/src/common/file_utils.dart @@ -22,9 +22,11 @@ File childFileWithSubcomponents(Directory base, List components) { /// childFileWithSubcomponents(rootDir, ['foo', 'bar']) /// creates a File representing /rootDir/foo/bar/. Directory childDirectoryWithSubcomponents( - Directory base, List components) { - Directory dir = base; - for (final String directoryName in components) { + Directory base, + List components, +) { + var dir = base; + for (final directoryName in components) { dir = dir.childDirectory(directoryName); } return dir; diff --git a/script/tool/lib/src/common/flutter_command_utils.dart b/script/tool/lib/src/common/flutter_command_utils.dart index fdc859002ada..185a005c0587 100644 --- a/script/tool/lib/src/common/flutter_command_utils.dart +++ b/script/tool/lib/src/common/flutter_command_utils.dart @@ -21,7 +21,7 @@ Future runConfigOnlyBuild( bool buildDebug = false, List extraArgs = const [], }) async { - final String flutterCommand = platform.isWindows ? 'flutter.bat' : 'flutter'; + final flutterCommand = platform.isWindows ? 'flutter.bat' : 'flutter'; final String target = switch (targetPlatform) { FlutterPlatform.android => 'apk', @@ -33,14 +33,15 @@ Future runConfigOnlyBuild( }; final int exitCode = await processRunner.runAndStream( - flutterCommand, - [ - 'build', - target, - if (buildDebug) '--debug', - '--config-only', - ...extraArgs, - ], - workingDir: package.directory); + flutterCommand, + [ + 'build', + target, + if (buildDebug) '--debug', + '--config-only', + ...extraArgs, + ], + workingDir: package.directory, + ); return exitCode == 0; } diff --git a/script/tool/lib/src/common/git_version_finder.dart b/script/tool/lib/src/common/git_version_finder.dart index fef25af26a5c..f7664e9a684f 100644 --- a/script/tool/lib/src/common/git_version_finder.dart +++ b/script/tool/lib/src/common/git_version_finder.dart @@ -12,10 +12,12 @@ import 'package:yaml/yaml.dart'; class GitVersionFinder { /// Constructor GitVersionFinder(this.baseGitDir, {String? baseSha, String? baseBranch}) - : assert(baseSha == null || baseBranch == null, - 'At most one of baseSha and baseBranch can be provided'), - _baseSha = baseSha, - _baseBranch = baseBranch ?? 'main'; + : assert( + baseSha == null || baseBranch == null, + 'At most one of baseSha and baseBranch can be provided', + ), + _baseSha = baseSha, + _baseBranch = baseBranch ?? 'main'; /// The top level directory of the git repo. /// @@ -29,17 +31,14 @@ class GitVersionFinder { final String _baseBranch; /// Get a list of all the changed files. - Future> getChangedFiles( - {bool includeUncommitted = false}) async { + Future> getChangedFiles({ + bool includeUncommitted = false, + }) async { final String baseSha = await getBaseSha(); - final io.ProcessResult changedFilesCommand = await baseGitDir - .runCommand([ - 'diff', - '--name-only', - baseSha, - if (!includeUncommitted) 'HEAD' - ]); - final String changedFilesStdout = changedFilesCommand.stdout.toString(); + final io.ProcessResult changedFilesCommand = await baseGitDir.runCommand( + ['diff', '--name-only', baseSha, if (!includeUncommitted) 'HEAD'], + ); + final changedFilesStdout = changedFilesCommand.stdout.toString(); if (changedFilesStdout.isEmpty) { return []; } @@ -60,7 +59,7 @@ class GitVersionFinder { if (!includeUncommitted) 'HEAD', if (targetPath != null) ...['--', targetPath], ]); - final String diffStdout = diffCommand.stdout.toString(); + final diffStdout = diffCommand.stdout.toString(); if (diffStdout.isEmpty) { return []; } @@ -71,23 +70,27 @@ class GitVersionFinder { /// Get the package version specified in the pubspec file in `pubspecPath` and /// at the revision of `gitRef` (defaulting to the base if not provided). - Future getPackageVersion(String pubspecPath, - {String? gitRef}) async { + Future getPackageVersion( + String pubspecPath, { + String? gitRef, + }) async { final String ref = gitRef ?? (await getBaseSha()); io.ProcessResult gitShow; try { - gitShow = - await baseGitDir.runCommand(['show', '$ref:$pubspecPath']); + gitShow = await baseGitDir.runCommand([ + 'show', + '$ref:$pubspecPath', + ]); } on io.ProcessException { return null; } - final String fileContent = gitShow.stdout as String; + final fileContent = gitShow.stdout as String; if (fileContent.trim().isEmpty) { return null; } - final YamlMap fileYaml = loadYaml(fileContent) as YamlMap; - final String? versionString = fileYaml['version'] as String?; + final fileYaml = loadYaml(fileContent) as YamlMap; + final versionString = fileYaml['version'] as String?; return versionString == null ? null : Version.parse(versionString); } @@ -99,13 +102,17 @@ class GitVersionFinder { } io.ProcessResult baseShaFromMergeBase = await baseGitDir.runCommand( - ['merge-base', '--fork-point', _baseBranch, 'HEAD'], - throwOnError: false); + ['merge-base', '--fork-point', _baseBranch, 'HEAD'], + throwOnError: false, + ); final String stdout = (baseShaFromMergeBase.stdout as String? ?? '').trim(); final String stderr = (baseShaFromMergeBase.stderr as String? ?? '').trim(); if (stderr.isNotEmpty || stdout.isEmpty) { - baseShaFromMergeBase = await baseGitDir - .runCommand(['merge-base', _baseBranch, 'HEAD']); + baseShaFromMergeBase = await baseGitDir.runCommand([ + 'merge-base', + _baseBranch, + 'HEAD', + ]); } baseSha = (baseShaFromMergeBase.stdout as String).trim(); _baseSha = baseSha; diff --git a/script/tool/lib/src/common/gradle.dart b/script/tool/lib/src/common/gradle.dart index e88b84483b6a..0d326677a105 100644 --- a/script/tool/lib/src/common/gradle.dart +++ b/script/tool/lib/src/common/gradle.dart @@ -36,7 +36,8 @@ class GradleProject { /// The path to the Gradle wrapper file for the project. File get gradleWrapper => androidDirectory.childFile( - platform.isWindows ? _gradleWrapperWindows : _gradleWrapperNonWindows); + platform.isWindows ? _gradleWrapperWindows : _gradleWrapperNonWindows, + ); /// Whether or not the project is ready to have Gradle commands run on it /// (i.e., whether the `flutter` tool has generated the necessary files). @@ -48,10 +49,10 @@ class GradleProject { List additionalTasks = const [], List arguments = const [], }) { - return processRunner.runAndStream( - gradleWrapper.path, - [task, ...additionalTasks, ...arguments], - workingDir: androidDirectory, - ); + return processRunner.runAndStream(gradleWrapper.path, [ + task, + ...additionalTasks, + ...arguments, + ], workingDir: androidDirectory); } } diff --git a/script/tool/lib/src/common/package_command.dart b/script/tool/lib/src/common/package_command.dart index a71deddfbeed..77f91c069bbf 100644 --- a/script/tool/lib/src/common/package_command.dart +++ b/script/tool/lib/src/common/package_command.dart @@ -60,7 +60,8 @@ abstract class PackageCommand extends Command { ); argParser.addOption( _shardIndexArg, - help: 'Specifies the zero-based index of the shard to ' + help: + 'Specifies the zero-based index of the shard to ' 'which the command applies.', valueHelp: 'i', defaultsTo: '0', @@ -71,69 +72,94 @@ abstract class PackageCommand extends Command { valueHelp: 'n', defaultsTo: '1', ); - argParser.addFlag(_exactMatchOnlyArg, - help: 'Disables package group matching in package selection.', - negatable: false); + argParser.addFlag( + _exactMatchOnlyArg, + help: 'Disables package group matching in package selection.', + negatable: false, + ); argParser.addMultiOption( _excludeArg, abbr: 'e', - help: 'A list of packages to exclude from this command.\n\n' + help: + 'A list of packages to exclude from this command.\n\n' 'Alternately, a list of one or more YAML files that contain a list ' 'of packages to exclude.', defaultsTo: [], ); - argParser.addFlag(_runOnChangedPackagesArg, - negatable: false, - help: 'Run the command on changed packages.\n' - 'If no packages have changed, or if there have been changes that may\n' - 'affect all packages, the command runs on all packages.\n' - 'Packages excluded with $_excludeArg are excluded even if changed.\n' - 'See $_baseShaArg if a custom base is needed to determine the diff.\n\n' - 'Cannot be combined with $_packagesArg.\n'); - argParser.addFlag(_runOnDirtyPackagesArg, - negatable: false, - help: - 'Run the command on packages with changes that have not been committed.\n' - 'Packages excluded with $_excludeArg are excluded even if changed.\n' - 'Cannot be combined with $_packagesArg.\n', - hide: true); - argParser.addFlag(_packagesForBranchArg, - negatable: false, - help: 'This runs on all packages changed in the last commit on main ' - '(or master), and behaves like --run-on-changed-packages on ' - 'any other branch.\n\n' - 'Cannot be combined with $_packagesArg.\n\n' - 'This is intended for use in CI.\n', - hide: true); - argParser.addMultiOption(_filterPackagesArg, - help: 'Filters any selected packages to only those included in this ' - 'list. This is intended for use in CI with flags such as ' - '--$_packagesForBranchArg.\n\n' - 'Entries can be package names or YAML files that contain a list ' - 'of package names.', - defaultsTo: [], - hide: true); - argParser.addFlag(_currentPackageArg, - negatable: false, - help: - 'Set the target package(s) based on the current working directory.\n' - '- If the current working directory is (or is inside) a package, ' - 'that package will be targeted.\n' - '- If the current working directory is the root of a federated ' - 'plugin group, that group will be targeted.\n' - 'Cannot be combined with $_packagesArg.\n'); - argParser.addOption(_baseShaArg, - help: 'The base sha used to determine git diff. \n' - 'This is useful when $_runOnChangedPackagesArg is specified.\n' - 'If not specified, merge-base is used as base sha.'); - argParser.addOption(_baseBranchArg, - help: 'The base branch whose merge base is used as the base SHA if ' - '--$_baseShaArg is not provided. \n' - 'If not specified, "main" is used as the base branch.'); - argParser.addFlag(_logTimingArg, - help: 'Logs timing information.\n\n' - 'Currently only logs per-package timing for multi-package commands, ' - 'but more information may be added in the future.'); + argParser.addFlag( + _runOnChangedPackagesArg, + negatable: false, + help: + 'Run the command on changed packages.\n' + 'If no packages have changed, or if there have been changes that may\n' + 'affect all packages, the command runs on all packages.\n' + 'Packages excluded with $_excludeArg are excluded even if changed.\n' + 'See $_baseShaArg if a custom base is needed to determine the diff.\n\n' + 'Cannot be combined with $_packagesArg.\n', + ); + argParser.addFlag( + _runOnDirtyPackagesArg, + negatable: false, + help: + 'Run the command on packages with changes that have not been committed.\n' + 'Packages excluded with $_excludeArg are excluded even if changed.\n' + 'Cannot be combined with $_packagesArg.\n', + hide: true, + ); + argParser.addFlag( + _packagesForBranchArg, + negatable: false, + help: + 'This runs on all packages changed in the last commit on main ' + '(or master), and behaves like --run-on-changed-packages on ' + 'any other branch.\n\n' + 'Cannot be combined with $_packagesArg.\n\n' + 'This is intended for use in CI.\n', + hide: true, + ); + argParser.addMultiOption( + _filterPackagesArg, + help: + 'Filters any selected packages to only those included in this ' + 'list. This is intended for use in CI with flags such as ' + '--$_packagesForBranchArg.\n\n' + 'Entries can be package names or YAML files that contain a list ' + 'of package names.', + defaultsTo: [], + hide: true, + ); + argParser.addFlag( + _currentPackageArg, + negatable: false, + help: + 'Set the target package(s) based on the current working directory.\n' + '- If the current working directory is (or is inside) a package, ' + 'that package will be targeted.\n' + '- If the current working directory is the root of a federated ' + 'plugin group, that group will be targeted.\n' + 'Cannot be combined with $_packagesArg.\n', + ); + argParser.addOption( + _baseShaArg, + help: + 'The base sha used to determine git diff. \n' + 'This is useful when $_runOnChangedPackagesArg is specified.\n' + 'If not specified, merge-base is used as base sha.', + ); + argParser.addOption( + _baseBranchArg, + help: + 'The base branch whose merge base is used as the base SHA if ' + '--$_baseShaArg is not provided. \n' + 'If not specified, "main" is used as the base branch.', + ); + argParser.addFlag( + _logTimingArg, + help: + 'Logs timing information.\n\n' + 'Currently only logs per-package timing for multi-package commands, ' + 'but more information may be added in the future.', + ); } // Package selection. @@ -219,8 +245,10 @@ abstract class PackageCommand extends Command { printError('$packagesPath is not a valid Git repository.'); throw ToolExit(2); } - gitDir = - await GitDir.fromExisting(packagesDir.path, allowSubdirectory: true); + gitDir = await GitDir.fromExisting( + packagesDir.path, + allowSubdirectory: true, + ); _gitDir = gitDir; return gitDir; } @@ -287,7 +315,8 @@ abstract class PackageCommand extends Command { } if (shardIndex < 0 || shardCount <= shardIndex) { usageException( - '$_shardIndexArg must be in the half-open range [0..$shardCount['); + '$_shardIndexArg must be in the half-open range [0..$shardCount[', + ); } _shardIndex = shardIndex; _shardCount = shardCount; @@ -311,23 +340,29 @@ abstract class PackageCommand extends Command { /// /// By default, packages excluded via --exclude will not be in the stream, but /// they can be included by passing false for [filterExcluded]. - Stream getTargetPackages( - {bool filterExcluded = true}) async* { + Stream getTargetPackages({ + bool filterExcluded = true, + }) async* { // To avoid assuming consistency of `Directory.list` across command // invocations, we collect and sort the package folders before sharding. // This is considered an implementation detail which is why the API still // uses streams. - final List allPackages = - await _getAllPackages().toList(); - allPackages.sort((PackageEnumerationEntry p1, PackageEnumerationEntry p2) => - p1.package.path.compareTo(p2.package.path)); - final int shardSize = allPackages.length ~/ shardCount + + final List allPackages = await _getAllPackages() + .toList(); + allPackages.sort( + (PackageEnumerationEntry p1, PackageEnumerationEntry p2) => + p1.package.path.compareTo(p2.package.path), + ); + final int shardSize = + allPackages.length ~/ shardCount + (allPackages.length % shardCount == 0 ? 0 : 1); final int start = min(shardIndex * shardSize, allPackages.length); final int end = min(start + shardSize, allPackages.length); - for (final PackageEnumerationEntry package - in allPackages.sublist(start, end)) { + for (final PackageEnumerationEntry package in allPackages.sublist( + start, + end, + )) { if (!(filterExcluded && package.excluded)) { yield package; } @@ -358,7 +393,7 @@ abstract class PackageCommand extends Command { /// is a sibling of the packages directory. This is used for a small number /// of packages in the flutter/packages repository. Stream _getAllPackages() async* { - final Set packageSelectionFlags = { + final packageSelectionFlags = { _packagesArg, _runOnChangedPackagesArg, _runOnDirtyPackagesArg, @@ -369,9 +404,11 @@ abstract class PackageCommand extends Command { .where((String flag) => argResults!.wasParsed(flag)) .length > 1) { - printError('Only one of the package selection arguments ' - '(${packageSelectionFlags.join(", ")}) ' - 'can be provided.'); + printError( + 'Only one of the package selection arguments ' + '(${packageSelectionFlags.join(", ")}) ' + 'can be provided.', + ); throw ToolExit(exitInvalidArguments); } @@ -379,12 +416,13 @@ abstract class PackageCommand extends Command { // rather than allowing package groups for federated plugins. Any cases // where the set of packages is determined programatically based on repo // state should use exact matching. - final bool allowGroupMatching = !(getBoolArg(_exactMatchOnlyArg) || - argResults!.wasParsed(_runOnChangedPackagesArg) || - argResults!.wasParsed(_runOnDirtyPackagesArg) || - argResults!.wasParsed(_packagesForBranchArg)); + final bool allowGroupMatching = + !(getBoolArg(_exactMatchOnlyArg) || + argResults!.wasParsed(_runOnChangedPackagesArg) || + argResults!.wasParsed(_runOnDirtyPackagesArg) || + argResults!.wasParsed(_packagesForBranchArg)); - Set packages = Set.from(getStringListArg(_packagesArg)); + var packages = Set.from(getStringListArg(_packagesArg)); final GitVersionFinder? changedFileFinder; if (getBoolArg(_runOnChangedPackagesArg)) { @@ -392,8 +430,10 @@ abstract class PackageCommand extends Command { } else if (getBoolArg(_packagesForBranchArg)) { final String? branch = await _getBranch(); if (branch == null) { - printError('Unable to determine branch; --$_packagesForBranchArg can ' - 'only be used in a git repository.'); + printError( + 'Unable to determine branch; --$_packagesForBranchArg can ' + 'only be used in a git repository.', + ); throw ToolExit(exitInvalidArguments); } else { // Configure the change finder the correct mode for the branch. @@ -405,7 +445,8 @@ abstract class PackageCommand extends Command { lastCommitOnly = true; } else if (await _isCheckoutFromBranch('main')) { print( - '--$_packagesForBranchArg: running on a commit from default branch.'); + '--$_packagesForBranchArg: running on a commit from default branch.', + ); lastCommitOnly = true; } else { print('--$_packagesForBranchArg: running on branch "$branch".'); @@ -413,7 +454,8 @@ abstract class PackageCommand extends Command { } if (lastCommitOnly) { print( - '--$_packagesForBranchArg: using parent commit as the diff base.'); + '--$_packagesForBranchArg: using parent commit as the diff base.', + ); changedFileFinder = GitVersionFinder(await gitDir, baseSha: 'HEAD~'); } else { changedFileFinder = await retrieveVersionFinder(); @@ -425,25 +467,28 @@ abstract class PackageCommand extends Command { if (changedFileFinder != null) { final String baseSha = await changedFileFinder.getBaseSha(); - final List changedFiles = - await changedFileFinder.getChangedFiles(); + final List changedFiles = await changedFileFinder + .getChangedFiles(); if (_changesRequireFullTest(changedFiles)) { - print('Running for all packages, since a file has changed that could ' - 'affect the entire repository.'); + print( + 'Running for all packages, since a file has changed that could ' + 'affect the entire repository.', + ); } else { print( - 'Running for all packages that have diffs relative to "$baseSha"\n'); + 'Running for all packages that have diffs relative to "$baseSha"\n', + ); packages = _getChangedPackageNames(changedFiles); } } else if (getBoolArg(_runOnDirtyPackagesArg)) { - final GitVersionFinder gitVersionFinder = - GitVersionFinder(await gitDir, baseSha: 'HEAD'); + final gitVersionFinder = GitVersionFinder(await gitDir, baseSha: 'HEAD'); print('Running for all packages that have uncommitted changes\n'); // _changesRequireFullTest is deliberately not used here, as this flag is // intended for use in CI to re-test packages changed by // 'make-deps-path-based'. packages = _getChangedPackageNames( - await gitVersionFinder.getChangedFiles(includeUncommitted: true)); + await gitVersionFinder.getChangedFiles(includeUncommitted: true), + ); // For the same reason, empty is not treated as "all packages" as it is // for other flags. if (packages.isEmpty) { @@ -452,8 +497,10 @@ abstract class PackageCommand extends Command { } else if (getBoolArg(_currentPackageArg)) { final String? currentPackageName = _getCurrentDirectoryPackageName(); if (currentPackageName == null) { - printError('Unable to determine packages; --$_currentPackageArg can ' - 'only be used within a repository package or package group.'); + printError( + 'Unable to determine packages; --$_currentPackageArg can ' + 'only be used within a repository package or package group.', + ); throw ToolExit(exitInvalidArguments); } packages = {currentPackageName}; @@ -461,14 +508,17 @@ abstract class PackageCommand extends Command { final Set excludedPackageNames = getExcludedPackageNames(); final bool hasFilter = argResults?.wasParsed(_filterPackagesArg) ?? false; - final Set? excludeAllButPackageNames = - hasFilter ? getYamlListArg(_filterPackagesArg) : null; + final Set? excludeAllButPackageNames = hasFilter + ? getYamlListArg(_filterPackagesArg) + : null; if (excludeAllButPackageNames != null && excludeAllButPackageNames.isNotEmpty) { final List sortedList = excludeAllButPackageNames.toList() ..sort(); - print('--$_filterPackagesArg is excluding packages that are not ' - 'included in: ${sortedList.join(',')}'); + print( + '--$_filterPackagesArg is excluding packages that are not ' + 'included in: ${sortedList.join(',')}', + ); } // Returns true if a package that could be identified by any of // `possibleNames` should be excluded. @@ -483,13 +533,21 @@ abstract class PackageCommand extends Command { await for (final RepositoryPackage package in _everyTopLevelPackage()) { if (packages.isEmpty || packages - .intersection(_possiblePackageIdentifiers(package, - allowGroup: allowGroupMatching)) + .intersection( + _possiblePackageIdentifiers( + package, + allowGroup: allowGroupMatching, + ), + ) .isNotEmpty) { // Exclusion is always human input, so groups should always be allowed // unless they have been specifically forbidden. - final bool excluded = isExcluded(_possiblePackageIdentifiers(package, - allowGroup: !getBoolArg(_exactMatchOnlyArg))); + final bool excluded = isExcluded( + _possiblePackageIdentifiers( + package, + allowGroup: !getBoolArg(_exactMatchOnlyArg), + ), + ); yield PackageEnumerationEntry(package, excluded: excluded); } } @@ -504,20 +562,22 @@ abstract class PackageCommand extends Command { /// - Every package that is a direct child of a non-package subdirectory of /// one of those directories (to cover federated plugin groups). Stream _everyTopLevelPackage() async* { - for (final Directory dir in [ + for (final dir in [ packagesDir, if (thirdPartyPackagesDir.existsSync()) thirdPartyPackagesDir, ]) { - await for (final FileSystemEntity entity - in dir.list(followLinks: false)) { + await for (final FileSystemEntity entity in dir.list( + followLinks: false, + )) { // A top-level Dart package is a standard package. if (isPackage(entity)) { yield RepositoryPackage(entity as Directory); } else if (entity is Directory) { // Look for Dart packages under this top-level directory; this is the // standard structure for federated plugins. - await for (final FileSystemEntity subdir - in entity.list(followLinks: false)) { + await for (final FileSystemEntity subdir in entity.list( + followLinks: false, + )) { if (isPackage(subdir)) { yield RepositoryPackage(subdir as Directory); } @@ -541,8 +601,10 @@ abstract class PackageCommand extends Command { final io.Directory parentDir = package.directory.parent; return { packageName, - path.relative(package.path, - from: parentDir.parent.path), // fully specified + path.relative( + package.path, + from: parentDir.parent.path, + ), // fully specified if (allowGroup) path.basename(parentDir.path), // group name }; } else { @@ -558,15 +620,19 @@ abstract class PackageCommand extends Command { /// /// Subpackages are guaranteed to be after the containing package in the /// stream. - Stream getTargetPackagesAndSubpackages( - {bool filterExcluded = true}) async* { - await for (final PackageEnumerationEntry package - in getTargetPackages(filterExcluded: filterExcluded)) { + Stream getTargetPackagesAndSubpackages({ + bool filterExcluded = true, + }) async* { + await for (final PackageEnumerationEntry package in getTargetPackages( + filterExcluded: filterExcluded, + )) { yield package; - yield* Stream.fromIterable(package.package - .getSubpackages() - .map((RepositoryPackage subPackage) => - PackageEnumerationEntry(subPackage, excluded: package.excluded))); + yield* Stream.fromIterable( + package.package.getSubpackages().map( + (RepositoryPackage subPackage) => + PackageEnumerationEntry(subPackage, excluded: package.excluded), + ), + ); } } @@ -574,7 +640,8 @@ abstract class PackageCommand extends Command { /// involved in this command execution. Stream getFiles() { return getTargetPackages().asyncExpand( - (PackageEnumerationEntry entry) => getFilesForPackage(entry.package)); + (PackageEnumerationEntry entry) => getFilesForPackage(entry.package), + ); } /// Returns the files contained, recursively, within [package]. @@ -590,11 +657,15 @@ abstract class PackageCommand extends Command { /// Throws tool exit if [gitDir] nor root directory is a git directory. Future retrieveVersionFinder() async { final String? baseSha = getNullableStringArg(_baseShaArg); - final String? baseBranch = - baseSha == null ? getNullableStringArg(_baseBranchArg) : null; - - final GitVersionFinder gitVersionFinder = GitVersionFinder(await gitDir, - baseSha: baseSha, baseBranch: baseBranch); + final String? baseBranch = baseSha == null + ? getNullableStringArg(_baseBranchArg) + : null; + + final gitVersionFinder = GitVersionFinder( + await gitDir, + baseSha: baseSha, + baseBranch: baseBranch, + ); return gitVersionFinder; } @@ -607,7 +678,7 @@ abstract class PackageCommand extends Command { // // The paths must use POSIX separators (e.g., as provided by git output). Set _getChangedPackageNames(List changedFiles) { - final Set packages = {}; + final packages = {}; // A helper function that returns true if candidatePackageName looks like an // implementation package of a plugin called pluginName. Used to determine @@ -619,19 +690,22 @@ abstract class PackageCommand extends Command { candidatePackageName.startsWith('${parentName}_'); } - for (final String path in changedFiles) { + for (final path in changedFiles) { final List pathComponents = p.posix.split(path); - final int packagesIndex = - pathComponents.indexWhere((String element) => element == 'packages'); + final int packagesIndex = pathComponents.indexWhere( + (String element) => element == 'packages', + ); if (packagesIndex != -1) { // Find the name of the directory directly under packages. This is // either the name of the package, or a plugin group directory for // a federated plugin. final String topLevelName = pathComponents[packagesIndex + 1]; - String packageName = topLevelName; + var packageName = topLevelName; if (packagesIndex + 2 < pathComponents.length && isFederatedPackage( - pathComponents[packagesIndex + 2], topLevelName)) { + pathComponents[packagesIndex + 2], + topLevelName, + )) { // This looks like a federated package; use the full specifier if // the name would be ambiguous (i.e., for the app-facing package). packageName = pathComponents[packagesIndex + 2]; @@ -652,7 +726,7 @@ abstract class PackageCommand extends Command { } String? _getCurrentDirectoryPackageName() { - final Set absolutePackagesDirs = { + final absolutePackagesDirs = { packagesDir.absolute, thirdPartyPackagesDir.absolute, }; @@ -663,8 +737,9 @@ abstract class PackageCommand extends Command { // Ensure that the current directory is within one of the top-level packages // directories. if (isATopLevelPackagesDir(currentDir) || - !absolutePackagesDirs - .any((Directory d) => currentDir.path.startsWith(d.path))) { + !absolutePackagesDirs.any( + (Directory d) => currentDir.path.startsWith(d.path), + )) { return null; } // If the current directory is a direct subdirectory of a packages @@ -680,7 +755,7 @@ abstract class PackageCommand extends Command { } } // ... and then check whether it has an enclosing package. - final RepositoryPackage package = RepositoryPackage(currentDir); + final package = RepositoryPackage(currentDir); final RepositoryPackage? enclosingPackage = package.getEnclosingPackage(); final RepositoryPackage rootPackage = enclosingPackage ?? package; final String name = rootPackage.directory.basename; @@ -700,15 +775,18 @@ abstract class PackageCommand extends Command { Future _isCheckoutFromBranch(String branchName) async { // The target branch may not exist locally; try some common remote names for // the branch as well. - final List candidateBranchNames = [ + final candidateBranchNames = [ branchName, 'origin/$branchName', 'upstream/$branchName', ]; - for (final String branch in candidateBranchNames) { - final io.ProcessResult result = await (await gitDir).runCommand( - ['merge-base', '--is-ancestor', 'HEAD', branch], - throwOnError: false); + for (final branch in candidateBranchNames) { + final io.ProcessResult result = await (await gitDir).runCommand([ + 'merge-base', + '--is-ancestor', + 'HEAD', + branch, + ], throwOnError: false); if (result.exitCode == 0) { return true; } else if (result.exitCode == 1) { @@ -724,8 +802,9 @@ abstract class PackageCommand extends Command { Future _getBranch() async { final io.ProcessResult branchResult = await (await gitDir).runCommand( - ['rev-parse', '--abbrev-ref', 'HEAD'], - throwOnError: false); + ['rev-parse', '--abbrev-ref', 'HEAD'], + throwOnError: false, + ); if (branchResult.exitCode != 0) { return null; } @@ -735,12 +814,12 @@ abstract class PackageCommand extends Command { // Returns true if one or more files changed that have the potential to affect // any packages (e.g., CI script changes). bool _changesRequireFullTest(List changedFiles) { - const List specialFiles = [ + const specialFiles = [ '.ci.yaml', // LUCI config. '.clang-format', // ObjC and C/C++ formatting options. 'analysis_options.yaml', // Dart analysis settings. ]; - const List specialDirectories = [ + const specialDirectories = [ '.ci/', // Support files for CI. 'script/', // This tool. ]; @@ -748,8 +827,10 @@ abstract class PackageCommand extends Command { // check below is done via string prefixing. assert(specialDirectories.every((String dir) => dir.endsWith('/'))); - return changedFiles.any((String path) => - specialFiles.contains(path) || - specialDirectories.any((String dir) => path.startsWith(dir))); + return changedFiles.any( + (String path) => + specialFiles.contains(path) || + specialDirectories.any((String dir) => path.startsWith(dir)), + ); } } diff --git a/script/tool/lib/src/common/package_looping_command.dart b/script/tool/lib/src/common/package_looping_command.dart index 817142c01ca5..3aa518a9012a 100644 --- a/script/tool/lib/src/common/package_looping_command.dart +++ b/script/tool/lib/src/common/package_looping_command.dart @@ -51,7 +51,7 @@ class PackageResult { /// A run that was skipped as explained in [reason]. PackageResult.skip(String reason) - : this._(RunState.skipped, [reason]); + : this._(RunState.skipped, [reason]); /// A run that was excluded by the command invocation. PackageResult.exclude() : this._(RunState.excluded); @@ -61,7 +61,7 @@ class PackageResult { /// If [errors] are provided, they will be listed in the summary, otherwise /// the summary will simply show that the package failed. PackageResult.fail([List errors = const []]) - : this._(RunState.failed, errors); + : this._(RunState.failed, errors); const PackageResult._(this.state, [this.details = const []]); @@ -90,7 +90,8 @@ abstract class PackageLoopingCommand extends PackageCommand { }) { argParser.addOption( _skipByFlutterVersionArg, - help: 'Skip any packages that require a Flutter version newer than ' + help: + 'Skip any packages that require a Flutter version newer than ' 'the provided version, or a Dart version newer than the ' 'corresponding Dart version.', ); @@ -142,12 +143,14 @@ abstract class PackageLoopingCommand extends PackageCommand { await for (final PackageEnumerationEntry packageEntry in getTargetPackages(filterExcluded: false)) { yield packageEntry; - yield* Stream.fromIterable(packageEntry - .package - .getExamples() - .map((RepositoryPackage package) => PackageEnumerationEntry( - package, - excluded: packageEntry.excluded))); + yield* Stream.fromIterable( + packageEntry.package.getExamples().map( + (RepositoryPackage package) => PackageEnumerationEntry( + package, + excluded: packageEntry.excluded, + ), + ), + ); } case PackageLoopingType.includeAllSubpackages: yield* getTargetPackagesAndSubpackages(filterExcluded: false); @@ -258,13 +261,16 @@ abstract class PackageLoopingCommand extends PackageCommand { Future run() async { bool succeeded; if (captureOutput) { - final List output = []; - final ZoneSpecification logSwitchSpecification = ZoneSpecification( - print: (Zone self, ZoneDelegate parent, Zone zone, String message) { - output.add(message); - }); - succeeded = await runZoned>(_runInternal, - zoneSpecification: logSwitchSpecification); + final output = []; + final logSwitchSpecification = ZoneSpecification( + print: (Zone self, ZoneDelegate parent, Zone zone, String message) { + output.add(message); + }, + ); + succeeded = await runZoned>( + _runInternal, + zoneSpecification: logSwitchSpecification, + ); await handleCapturedOutput(output); } else { succeeded = await _runInternal(); @@ -288,7 +294,7 @@ abstract class PackageLoopingCommand extends PackageCommand { ? null : getDartSdkForFlutterSdk(minFlutterVersion); - final DateTime runStart = DateTime.now(); + final runStart = DateTime.now(); // Populate the list of changed files for subclasses to use. final GitVersionFinder gitVersionFinder = await retrieveVersionFinder(); @@ -298,8 +304,9 @@ abstract class PackageLoopingCommand extends PackageCommand { // Check whether the command needs to run. if (changedFiles.isNotEmpty && changedFiles.every(shouldIgnoreFile)) { _printColorized( - 'SKIPPING ALL PACKAGES: No changed files affect this command', - Styles.DARK_GRAY); + 'SKIPPING ALL PACKAGES: No changed files affect this command', + Styles.DARK_GRAY, + ); return true; } @@ -308,10 +315,9 @@ abstract class PackageLoopingCommand extends PackageCommand { final List targetPackages = await getPackagesToProcess().toList(); - final Map results = - {}; - for (final PackageEnumerationEntry entry in targetPackages) { - final DateTime packageStart = DateTime.now(); + final results = {}; + for (final entry in targetPackages) { + final packageStart = DateTime.now(); _currentPackageEntry = entry; _printPackageHeading(entry, startTime: runStart); @@ -324,17 +330,21 @@ abstract class PackageLoopingCommand extends PackageCommand { PackageResult result; try { - result = await _runForPackageIfSupported(entry.package, - minFlutterVersion: minFlutterVersion, - minDartVersion: minDartVersion); + result = await _runForPackageIfSupported( + entry.package, + minFlutterVersion: minFlutterVersion, + minDartVersion: minDartVersion, + ); } catch (e, stack) { printError(e.toString()); printError(stack.toString()); result = PackageResult.fail(['Unhandled exception']); } if (result.state == RunState.skipped) { - _printColorized('${indentation}SKIPPING: ${result.details.first}', - Styles.DARK_GRAY); + _printColorized( + '${indentation}SKIPPING: ${result.details.first}', + Styles.DARK_GRAY, + ); } results[entry] = result; @@ -343,9 +353,10 @@ abstract class PackageLoopingCommand extends PackageCommand { if (shouldLogTiming && hasLongOutput) { final Duration elapsedTime = DateTime.now().difference(packageStart); _printColorized( - '\n[${entry.package.displayName} completed in ' - '${elapsedTime.inMinutes}m ${elapsedTime.inSeconds % 60}s]', - Styles.DARK_GRAY); + '\n[${entry.package.displayName} completed in ' + '${elapsedTime.inMinutes}m ${elapsedTime.inSeconds % 60}s]', + Styles.DARK_GRAY, + ); } } _currentPackageEntry = null; @@ -354,8 +365,9 @@ abstract class PackageLoopingCommand extends PackageCommand { print('\n'); // If there were any errors reported, summarize them and exit. - if (results.values - .any((PackageResult result) => result.state == RunState.failed)) { + if (results.values.any( + (PackageResult result) => result.state == RunState.failed, + )) { _printFailureSummary(targetPackages, results); return false; } @@ -383,7 +395,8 @@ abstract class PackageLoopingCommand extends PackageCommand { if (flutterConstraint != null && !flutterConstraint.allows(minFlutterVersion)) { return PackageResult.skip( - 'Does not support Flutter $minFlutterVersion'); + 'Does not support Flutter $minFlutterVersion', + ); } } @@ -412,22 +425,26 @@ abstract class PackageLoopingCommand extends PackageCommand { /// Something is always printed to make it easier to distinguish between /// a command running for a package and producing no output, and a command /// not having been run for a package. - void _printPackageHeading(PackageEnumerationEntry entry, - {required DateTime startTime}) { + void _printPackageHeading( + PackageEnumerationEntry entry, { + required DateTime startTime, + }) { final String packageDisplayName = entry.package.displayName; - String heading = entry.excluded + var heading = entry.excluded ? 'Not running for $packageDisplayName; excluded' : 'Running for $packageDisplayName'; if (shouldLogTiming) { final Duration relativeTime = DateTime.now().difference(startTime); final String timeString = _formatDurationAsRelativeTime(relativeTime); - heading = - hasLongOutput ? '$heading [@$timeString]' : '[$timeString] $heading'; + heading = hasLongOutput + ? '$heading [@$timeString]' + : '[$timeString] $heading'; } if (hasLongOutput) { - heading = ''' + heading = + ''' ============================================================ || $heading @@ -440,15 +457,21 @@ abstract class PackageLoopingCommand extends PackageCommand { } /// Prints a summary of packges run, packages skipped, and warnings. - void _printRunSummary(List packages, - Map results) { + void _printRunSummary( + List packages, + Map results, + ) { final Set skippedPackages = results.entries - .where((MapEntry entry) => - entry.value.state == RunState.skipped) - .map((MapEntry entry) => - entry.key) + .where( + (MapEntry entry) => + entry.value.state == RunState.skipped, + ) + .map( + (MapEntry entry) => entry.key, + ) .toSet(); - final int skipCount = skippedPackages.length + + final int skipCount = + skippedPackages.length + packages .where((PackageEnumerationEntry package) => package.excluded) .length; @@ -460,16 +483,19 @@ abstract class PackageLoopingCommand extends PackageCommand { final int runWarningCount = _packagesWithWarnings.length - skippedWarningCount; - final String runWarningSummary = - runWarningCount > 0 ? ' ($runWarningCount with warnings)' : ''; - final String skippedWarningSummary = - runWarningCount > 0 ? ' ($skippedWarningCount with warnings)' : ''; + final runWarningSummary = runWarningCount > 0 + ? ' ($runWarningCount with warnings)' + : ''; + final skippedWarningSummary = runWarningCount > 0 + ? ' ($skippedWarningCount with warnings)' + : ''; print('------------------------------------------------------------'); if (hasLongOutput) { _printPerPackageRunOverview(packages, skipped: skippedPackages); } print( - 'Ran for ${packages.length - skipCount} package(s)$runWarningSummary'); + 'Ran for ${packages.length - skipCount} package(s)$runWarningSummary', + ); if (skipCount > 0) { print('Skipped $skipCount package(s)$skippedWarningSummary'); } @@ -481,10 +507,11 @@ abstract class PackageLoopingCommand extends PackageCommand { /// Prints a one-line-per-package overview of the run results for each /// package. void _printPerPackageRunOverview( - List packageEnumeration, - {required Set skipped}) { + List packageEnumeration, { + required Set skipped, + }) { print('Run overview:'); - for (final PackageEnumerationEntry entry in packageEnumeration) { + for (final entry in packageEnumeration) { final bool hadWarning = _packagesWithWarnings.contains(entry); Styles style; String summary; @@ -511,15 +538,17 @@ abstract class PackageLoopingCommand extends PackageCommand { } /// Prints a summary of all of the failures from [results]. - void _printFailureSummary(List packageEnumeration, - Map results) { - const String indentation = ' '; + void _printFailureSummary( + List packageEnumeration, + Map results, + ) { + const indentation = ' '; _printError(failureListHeader); - for (final PackageEnumerationEntry entry in packageEnumeration) { + for (final entry in packageEnumeration) { final PackageResult result = results[entry]!; if (result.state == RunState.failed) { final String errorIndentation = indentation * 2; - String errorDetails = ''; + var errorDetails = ''; if (result.details.isNotEmpty) { errorDetails = ':\n$errorIndentation${result.details.join('\n$errorIndentation')}'; diff --git a/script/tool/lib/src/common/package_state_utils.dart b/script/tool/lib/src/common/package_state_utils.dart index a5ac2daeb8a0..8a728ad42d1e 100644 --- a/script/tool/lib/src/common/package_state_utils.dart +++ b/script/tool/lib/src/common/package_state_utils.dart @@ -54,15 +54,15 @@ Future checkPackageChangeState( required String relativePackagePath, GitVersionFinder? git, }) async { - final String packagePrefix = relativePackagePath.endsWith('/') + final packagePrefix = relativePackagePath.endsWith('/') ? relativePackagePath : '$relativePackagePath/'; - bool hasChanges = false; - bool hasChangelogChange = false; - bool needsVersionChange = false; - bool needsChangelogChange = false; - for (final String path in changedPaths) { + var hasChanges = false; + var hasChangelogChange = false; + var needsVersionChange = false; + var needsChangelogChange = false; + for (final path in changedPaths) { // Only consider files within the package. if (!path.startsWith(packagePrefix)) { continue; @@ -86,8 +86,10 @@ Future checkPackageChangeState( continue; } - final bool isUnpublishedExampleChange = - _isUnpublishedExampleChange(components, package); + final bool isUnpublishedExampleChange = _isUnpublishedExampleChange( + components, + package, + ); // Since examples of federated plugin implementations are only intended // for testing purposes, any unpublished example change in one of them is @@ -105,20 +107,21 @@ Future checkPackageChangeState( // Most changes that aren't developer-only need version changes. if ( - // One of a few special files example will be shown on pub.dev, but - // for anything else in the example, publishing isn't necessary (even - // if it is relevant to mention in the CHANGELOG for the future). - !isUnpublishedExampleChange) { + // One of a few special files example will be shown on pub.dev, but + // for anything else in the example, publishing isn't necessary (even + // if it is relevant to mention in the CHANGELOG for the future). + !isUnpublishedExampleChange) { needsVersionChange = true; } } } return PackageChangeState( - hasChanges: hasChanges, - hasChangelogChange: hasChangelogChange, - needsChangelogChange: needsChangelogChange, - needsVersionChange: needsVersionChange); + hasChanges: hasChanges, + hasChangelogChange: hasChangelogChange, + needsChangelogChange: needsChangelogChange, + needsVersionChange: needsVersionChange, + ); } bool _isTestChange(List pathComponents) { @@ -139,7 +142,9 @@ bool _isTestChange(List pathComponents) { // This is not exhastive; it currently only handles variations we actually have // in our repositories. bool _isUnpublishedExampleChange( - List pathComponents, RepositoryPackage package) { + List pathComponents, + RepositoryPackage package, +) { if (pathComponents.first != 'example') { return false; } @@ -148,14 +153,15 @@ bool _isUnpublishedExampleChange( return false; } - final Directory exampleDirectory = - package.directory.childDirectory('example'); + final Directory exampleDirectory = package.directory.childDirectory( + 'example', + ); // Check for example.md/EXAMPLE.md first, as that has priority. If it's // present, any other example file is unpublished. final bool hasExampleMd = exampleDirectory.childFile('example.md').existsSync() || - exampleDirectory.childFile('EXAMPLE.md').existsSync(); + exampleDirectory.childFile('EXAMPLE.md').existsSync(); if (hasExampleMd) { return !(exampleComponents.length == 1 && exampleComponents.first.toLowerCase() == 'example.md'); @@ -164,10 +170,10 @@ bool _isUnpublishedExampleChange( // Most packages have an example/lib/main.dart (or occasionally // example/main.dart), so check for that. The other naming variations aren't // currently used. - const String mainName = 'main.dart'; + const mainName = 'main.dart'; final bool hasExampleCode = exampleDirectory.childDirectory('lib').childFile(mainName).existsSync() || - exampleDirectory.childFile(mainName).existsSync(); + exampleDirectory.childFile(mainName).existsSync(); if (hasExampleCode) { // If there is an example main, only that example file is published. return !((exampleComponents.length == 1 && @@ -183,8 +189,11 @@ bool _isUnpublishedExampleChange( } // True if the change is only relevant to people working on the package. -Future _isDevChange(List pathComponents, - {GitVersionFinder? git, String? repoPath}) async { +Future _isDevChange( + List pathComponents, { + GitVersionFinder? git, + String? repoPath, +}) async { return _isTestChange(pathComponents) || // The top-level "tool" directory is for non-client-facing utility // code, such as test scripts. @@ -203,14 +212,20 @@ Future _isDevChange(List pathComponents, // Example build files are very unlikely to be interesting to clients. _isExampleBuildFile(pathComponents) || // Test-only gradle depenedencies don't affect clients. - await _isGradleTestDependencyChange(pathComponents, - git: git, repoPath: repoPath) || + await _isGradleTestDependencyChange( + pathComponents, + git: git, + repoPath: repoPath, + ) || // Implementation comments don't affect clients. // This check is currently Dart-only since that's the only place // this has come up in practice; it could be generalized to other // languages if needed. - await _isDartImplementationCommentChange(pathComponents, - git: git, repoPath: repoPath); + await _isDartImplementationCommentChange( + pathComponents, + git: git, + repoPath: repoPath, + ); } bool _isExampleBuildFile(List pathComponents) { @@ -230,8 +245,11 @@ bool _isExampleBuildFile(List pathComponents) { pathComponents.contains('pubspec.yaml'); } -Future _isGradleTestDependencyChange(List pathComponents, - {GitVersionFinder? git, String? repoPath}) async { +Future _isGradleTestDependencyChange( + List pathComponents, { + GitVersionFinder? git, + String? repoPath, +}) async { if (git == null) { return false; } @@ -239,11 +257,12 @@ Future _isGradleTestDependencyChange(List pathComponents, return false; } final List diff = await git.getDiffContents(targetPath: repoPath); - final RegExp changeLine = RegExp(r'^[+-] '); - final RegExp testDependencyLine = - RegExp(r'^[+-]\s*(?:androidT|t)estImplementation(?:\s|\()'); - bool foundTestDependencyChange = false; - for (final String line in diff) { + final changeLine = RegExp(r'^[+-] '); + final testDependencyLine = RegExp( + r'^[+-]\s*(?:androidT|t)estImplementation(?:\s|\()', + ); + var foundTestDependencyChange = false; + for (final line in diff) { if (!changeLine.hasMatch(line) || line.startsWith('--- ') || line.startsWith('+++ ')) { @@ -261,8 +280,11 @@ Future _isGradleTestDependencyChange(List pathComponents, // Returns true if the given file is a Dart file whose only changes are // implementation comments (i.e., not doc comments). -Future _isDartImplementationCommentChange(List pathComponents, - {GitVersionFinder? git, String? repoPath}) async { +Future _isDartImplementationCommentChange( + List pathComponents, { + GitVersionFinder? git, + String? repoPath, +}) async { if (git == null) { return false; } @@ -270,11 +292,11 @@ Future _isDartImplementationCommentChange(List pathComponents, return false; } final List diff = await git.getDiffContents(targetPath: repoPath); - final RegExp changeLine = RegExp(r'^[+-] '); - final RegExp whitespaceLine = RegExp(r'^[+-]\s*$'); - final RegExp nonDocCommentLine = RegExp(r'^[+-]\s*//\s'); - bool foundIgnoredChange = false; - for (final String line in diff) { + final changeLine = RegExp(r'^[+-] '); + final whitespaceLine = RegExp(r'^[+-]\s*$'); + final nonDocCommentLine = RegExp(r'^[+-]\s*//\s'); + var foundIgnoredChange = false; + for (final line in diff) { if (!changeLine.hasMatch(line) || line.startsWith('--- ') || line.startsWith('+++ ')) { diff --git a/script/tool/lib/src/common/plugin_utils.dart b/script/tool/lib/src/common/plugin_utils.dart index 84a941d114f7..cbce2df9a92f 100644 --- a/script/tool/lib/src/common/plugin_utils.dart +++ b/script/tool/lib/src/common/plugin_utils.dart @@ -38,15 +38,19 @@ bool pluginSupportsPlatform( RepositoryPackage plugin, { PlatformSupport? requiredMode, }) { - assert(platform == platformIOS || - platform == platformAndroid || - platform == platformWeb || - platform == platformMacOS || - platform == platformWindows || - platform == platformLinux); + assert( + platform == platformIOS || + platform == platformAndroid || + platform == platformWeb || + platform == platformMacOS || + platform == platformWindows || + platform == platformLinux, + ); - final YamlMap? platformEntry = - _readPlatformPubspecSectionForPlugin(platform, plugin); + final YamlMap? platformEntry = _readPlatformPubspecSectionForPlugin( + platform, + plugin, + ); if (platformEntry == null) { return false; } @@ -70,14 +74,16 @@ bool pluginHasNativeCodeForPlatform(String platform, RepositoryPackage plugin) { // Web plugins are always Dart-only. return false; } - final YamlMap? platformEntry = - _readPlatformPubspecSectionForPlugin(platform, plugin); + final YamlMap? platformEntry = _readPlatformPubspecSectionForPlugin( + platform, + plugin, + ); if (platformEntry == null) { return false; } // All other platforms currently use pluginClass for indicating the native // code in the plugin. - final String? pluginClass = platformEntry['pluginClass'] as String?; + final pluginClass = platformEntry['pluginClass'] as String?; // TODO(stuartmorgan): Remove the check for 'none' once none of the plugins // in the repository use that workaround. See // https://github.com/flutter/flutter/issues/57497 for context. @@ -89,16 +95,17 @@ bool pluginHasNativeCodeForPlatform(String platform, RepositoryPackage plugin) { /// /// A null enabled state clears the package-local override, defaulting to whatever the /// global state is. -void setSwiftPackageManagerState(RepositoryPackage package, - {required bool? enabled}) { - const String swiftPMFlag = 'enable-swift-package-manager'; - const String flutterKey = 'flutter'; - const List flutterPath = [flutterKey]; - const List configPath = [flutterKey, 'config']; +void setSwiftPackageManagerState( + RepositoryPackage package, { + required bool? enabled, +}) { + const swiftPMFlag = 'enable-swift-package-manager'; + const flutterKey = 'flutter'; + const flutterPath = [flutterKey]; + const configPath = [flutterKey, 'config']; - final YamlEditor editablePubspec = - YamlEditor(package.pubspecFile.readAsStringSync()); - final YamlMap configMap = + final editablePubspec = YamlEditor(package.pubspecFile.readAsStringSync()); + final configMap = editablePubspec.parseAt(configPath, orElse: () => YamlMap()) as YamlMap; if (enabled == null) { if (!configMap.containsKey(swiftPMFlag)) { @@ -110,8 +117,9 @@ void setSwiftPackageManagerState(RepositoryPackage package, editablePubspec.remove(configPath); // The entire flutter: section may also only have been added for the // config, in which case it should be removed as well. - final YamlMap flutterMap = editablePubspec.parseAt(flutterPath, - orElse: () => YamlMap()) as YamlMap; + final flutterMap = + editablePubspec.parseAt(flutterPath, orElse: () => YamlMap()) + as YamlMap; if (flutterMap.isEmpty) { editablePubspec.remove(flutterPath); } @@ -122,7 +130,7 @@ void setSwiftPackageManagerState(RepositoryPackage package, } else { // Ensure that the section exists. if (configMap.isEmpty) { - final YamlMap root = editablePubspec.parseAt([]) as YamlMap; + final root = editablePubspec.parseAt([]) as YamlMap; if (!root.containsKey(flutterKey)) { editablePubspec.update(flutterPath, YamlMap()); } @@ -143,12 +151,14 @@ void setSwiftPackageManagerState(RepositoryPackage package, /// section from [plugin]'s pubspec.yaml, or null if either it is not present, /// or the pubspec couldn't be read. YamlMap? _readPlatformPubspecSectionForPlugin( - String platform, RepositoryPackage plugin) { + String platform, + RepositoryPackage plugin, +) { final YamlMap? pluginSection = _readPluginPubspecSection(plugin); if (pluginSection == null) { return null; } - final YamlMap? platforms = pluginSection['platforms'] as YamlMap?; + final platforms = pluginSection['platforms'] as YamlMap?; if (platforms == null) { return null; } diff --git a/script/tool/lib/src/common/process_runner.dart b/script/tool/lib/src/common/process_runner.dart index b7f337988586..ce3280ad9a7c 100644 --- a/script/tool/lib/src/common/process_runner.dart +++ b/script/tool/lib/src/common/process_runner.dart @@ -34,14 +34,21 @@ class ProcessRunner { bool exitOnError = false, }) async { print( - 'Running command: "$executable ${args.join(' ')}" in ${workingDir?.path ?? io.Directory.current.path}'); - final io.Process process = await io.Process.start(executable, args, - workingDirectory: workingDir?.path, - environment: environment, - mode: io.ProcessStartMode.inheritStdio); + 'Running command: "$executable ${args.join(' ')}" in ${workingDir?.path ?? io.Directory.current.path}', + ); + final io.Process process = await io.Process.start( + executable, + args, + workingDirectory: workingDir?.path, + environment: environment, + mode: io.ProcessStartMode.inheritStdio, + ); if (exitOnError && await process.exitCode != 0) { - final String error = - _getErrorString(executable, args, workingDir: workingDir); + final String error = _getErrorString( + executable, + args, + workingDir: workingDir, + ); print('$error See above for details.'); throw ToolExit(await process.exitCode); } @@ -71,15 +78,21 @@ class ProcessRunner { Encoding stdoutEncoding = io.systemEncoding, Encoding stderrEncoding = io.systemEncoding, }) async { - final io.ProcessResult result = await io.Process.run(executable, args, - workingDirectory: workingDir?.path, - environment: environment, - stdoutEncoding: stdoutEncoding, - stderrEncoding: stderrEncoding); + final io.ProcessResult result = await io.Process.run( + executable, + args, + workingDirectory: workingDir?.path, + environment: environment, + stdoutEncoding: stdoutEncoding, + stderrEncoding: stderrEncoding, + ); if (result.exitCode != 0) { if (logOnError) { - final String error = - _getErrorString(executable, args, workingDir: workingDir); + final String error = _getErrorString( + executable, + args, + workingDir: workingDir, + ); print('$error Stderr:\n${result.stdout}'); } if (exitOnError) { @@ -95,16 +108,25 @@ class ProcessRunner { /// passing [workingDir]. /// /// Returns the started [io.Process]. - Future start(String executable, List args, - {Directory? workingDirectory}) async { - final io.Process process = await io.Process.start(executable, args, - workingDirectory: workingDirectory?.path); + Future start( + String executable, + List args, { + Directory? workingDirectory, + }) async { + final io.Process process = await io.Process.start( + executable, + args, + workingDirectory: workingDirectory?.path, + ); return process; } - String _getErrorString(String executable, List args, - {Directory? workingDir}) { - final String workdir = workingDir == null ? '' : ' in ${workingDir.path}'; + String _getErrorString( + String executable, + List args, { + Directory? workingDir, + }) { + final workdir = workingDir == null ? '' : ' in ${workingDir.path}'; return 'ERROR: Unable to execute "$executable ${args.join(' ')}"$workdir.'; } } diff --git a/script/tool/lib/src/common/pub_utils.dart b/script/tool/lib/src/common/pub_utils.dart index 7c66a87ded00..963a548aef68 100644 --- a/script/tool/lib/src/common/pub_utils.dart +++ b/script/tool/lib/src/common/pub_utils.dart @@ -19,22 +19,33 @@ import 'repository_package.dart'; /// If [streamOutput] is false, output will only be printed if the command /// fails. Future runPubGet( - RepositoryPackage package, ProcessRunner processRunner, Platform platform, - {bool alwaysUseFlutter = false, bool streamOutput = true}) async { + RepositoryPackage package, + ProcessRunner processRunner, + Platform platform, { + bool alwaysUseFlutter = false, + bool streamOutput = true, +}) async { // Running `dart pub get` on a Flutter package can fail if a non-Flutter Dart // is first in the path, so use `flutter pub get` for any Flutter package. final bool useFlutter = alwaysUseFlutter || package.requiresFlutter(); - final String command = - useFlutter ? (platform.isWindows ? 'flutter.bat' : 'flutter') : 'dart'; - final List args = ['pub', 'get']; + final command = useFlutter + ? (platform.isWindows ? 'flutter.bat' : 'flutter') + : 'dart'; + final args = ['pub', 'get']; final int exitCode; if (streamOutput) { - exitCode = await processRunner.runAndStream(command, args, - workingDir: package.directory); + exitCode = await processRunner.runAndStream( + command, + args, + workingDir: package.directory, + ); } else { - final io.ProcessResult result = - await processRunner.run(command, args, workingDir: package.directory); + final io.ProcessResult result = await processRunner.run( + command, + args, + workingDir: package.directory, + ); exitCode = result.exitCode; if (exitCode != 0) { print('${result.stdout}\n${result.stderr}\n'); diff --git a/script/tool/lib/src/common/pub_version_finder.dart b/script/tool/lib/src/common/pub_version_finder.dart index d7bdb9381517..e024158e3186 100644 --- a/script/tool/lib/src/common/pub_version_finder.dart +++ b/script/tool/lib/src/common/pub_version_finder.dart @@ -26,8 +26,9 @@ class PubVersionFinder { final http.Client httpClient; /// Get the package version on pub. - Future getPackageVersion( - {required String packageName}) async { + Future getPackageVersion({ + required String packageName, + }) async { assert(packageName.isNotEmpty); final Uri pubHostUri = Uri.parse(pubHost); final Uri url = pubHostUri.replace(path: '/packages/$packageName.json'); @@ -35,37 +36,41 @@ class PubVersionFinder { if (response.statusCode == 404) { return PubVersionFinderResponse( - versions: [], - result: PubVersionFinderResult.noPackageFound, - httpResponse: response); + versions: [], + result: PubVersionFinderResult.noPackageFound, + httpResponse: response, + ); } else if (response.statusCode != 200) { return PubVersionFinderResponse( - versions: [], - result: PubVersionFinderResult.fail, - httpResponse: response); + versions: [], + result: PubVersionFinderResult.fail, + httpResponse: response, + ); } - final Map responseBody = - json.decode(response.body) as Map; + final responseBody = json.decode(response.body) as Map; final List versions = (responseBody['versions']! as List) .cast() .map( - (final String versionString) => Version.parse(versionString)) + (final String versionString) => Version.parse(versionString), + ) .toList(); return PubVersionFinderResponse( - versions: versions, - result: PubVersionFinderResult.success, - httpResponse: response); + versions: versions, + result: PubVersionFinderResult.success, + httpResponse: response, + ); } } /// Represents a response for [PubVersionFinder]. class PubVersionFinderResponse { /// Constructor. - PubVersionFinderResponse( - {required this.versions, - required this.result, - required this.httpResponse}) { + PubVersionFinderResponse({ + required this.versions, + required this.result, + required this.httpResponse, + }) { if (versions.isNotEmpty) { versions.sort((Version a, Version b) { // TODO(cyanglaz): Think about how to handle pre-release version with [Version.prioritize]. diff --git a/script/tool/lib/src/common/repository_package.dart b/script/tool/lib/src/common/repository_package.dart index cbcd023743c5..0edbb03ca5f2 100644 --- a/script/tool/lib/src/common/repository_package.dart +++ b/script/tool/lib/src/common/repository_package.dart @@ -107,8 +107,9 @@ class RepositoryPackage { return platformDirectory(platform).existsSync(); } - late final Pubspec _parsedPubspec = - Pubspec.parse(pubspecFile.readAsStringSync()); + late final Pubspec _parsedPubspec = Pubspec.parse( + pubspecFile.readAsStringSync(), + ); /// Returns the parsed [pubspecFile]. /// @@ -117,7 +118,7 @@ class RepositoryPackage { /// Returns true if the package depends on Flutter. bool requiresFlutter() { - const String flutterDependency = 'flutter'; + const flutterDependency = 'flutter'; final Pubspec pubspec = parsePubspec(); return pubspec.dependencies.containsKey(flutterDependency) || pubspec.devDependencies.containsKey(flutterDependency); @@ -158,9 +159,9 @@ class RepositoryPackage { return false; } // Check whether this is one of the enclosing package's examples. - return enclosingPackage - .getExamples() - .any((RepositoryPackage p) => p.path == path); + return enclosingPackage.getExamples().any( + (RepositoryPackage p) => p.path == path, + ); } /// Returns the Flutter example packages contained in the package, if any. @@ -179,8 +180,9 @@ class RepositoryPackage { .listSync() .where((FileSystemEntity entity) => isPackage(entity)) // isPackage guarantees that the cast to Directory is safe. - .map((FileSystemEntity entity) => - RepositoryPackage(entity as Directory)); + .map( + (FileSystemEntity entity) => RepositoryPackage(entity as Directory), + ); } /// Returns the package that this package is a part of, if any. @@ -203,11 +205,15 @@ class RepositoryPackage { return directory .listSync(recursive: true, followLinks: false) .where(isPackage) - .map((FileSystemEntity directory) => - // isPackage guarantees that this cast is valid. - RepositoryPackage(directory as Directory)) - .where((RepositoryPackage p) => - includeExamples || (p.directory.basename != 'example')); + .map( + (FileSystemEntity directory) => + // isPackage guarantees that this cast is valid. + RepositoryPackage(directory as Directory), + ) + .where( + (RepositoryPackage p) => + includeExamples || (p.directory.basename != 'example'), + ); } /// Returns true if the package is not marked as "publish_to: none". diff --git a/script/tool/lib/src/common/xcode.dart b/script/tool/lib/src/common/xcode.dart index 9bbf82645405..dbcb952d2414 100644 --- a/script/tool/lib/src/common/xcode.dart +++ b/script/tool/lib/src/common/xcode.dart @@ -21,10 +21,7 @@ class Xcode { /// /// If [log] is true, commands run by this instance will long various status /// messages. - Xcode({ - this.processRunner = const ProcessRunner(), - this.log = false, - }); + Xcode({this.processRunner = const ProcessRunner(), this.log = false}); /// The [ProcessRunner] used to run commands. Overridable for testing. final ProcessRunner processRunner; @@ -49,8 +46,9 @@ class Xcode { Directory? resultBundleTemp; try { if (logsDirectory != null) { - resultBundleTemp = - fileSystem.systemTempDirectory.createTempSync('flutter_xcresult.'); + resultBundleTemp = fileSystem.systemTempDirectory.createTempSync( + 'flutter_xcresult.', + ); resultBundlePath = resultBundleTemp.childDirectory('result').path; } File? disabledSandboxEntitlementFile; @@ -60,49 +58,51 @@ class Xcode { configuration ?? 'Debug', ); } - final List args = [ + final args = [ _xcodeBuildCommand, ...actions, ...['-workspace', workspace], ...['-scheme', scheme], if (resultBundlePath != null) ...[ '-resultBundlePath', - resultBundlePath + resultBundlePath, ], if (configuration != null) ...['-configuration', configuration], ...extraFlags, if (disabledSandboxEntitlementFile != null) 'CODE_SIGN_ENTITLEMENTS=${disabledSandboxEntitlementFile.path}', ]; - final String completeTestCommand = '$_xcRunCommand ${args.join(' ')}'; + final completeTestCommand = '$_xcRunCommand ${args.join(' ')}'; if (log) { print(completeTestCommand); } - final int resultExit = await processRunner - .runAndStream(_xcRunCommand, args, workingDir: exampleDirectory); + final int resultExit = await processRunner.runAndStream( + _xcRunCommand, + args, + workingDir: exampleDirectory, + ); if (resultExit != 0 && resultBundleTemp != null) { - final Directory xcresultBundle = - resultBundleTemp.childDirectory('result.xcresult'); + final Directory xcresultBundle = resultBundleTemp.childDirectory( + 'result.xcresult', + ); if (logsDirectory != null) { if (xcresultBundle.existsSync()) { // Zip the test results to the artifacts directory for upload. final File zipPath = logsDirectory.childFile( - 'xcodebuild-${DateTime.now().toLocal().toIso8601String()}.zip'); - await processRunner.run( - 'zip', - [ - '-r', - '-9', - '-q', - zipPath.path, - xcresultBundle.basename, - ], - workingDir: resultBundleTemp, + 'xcodebuild-${DateTime.now().toLocal().toIso8601String()}.zip', ); + await processRunner.run('zip', [ + '-r', + '-9', + '-q', + zipPath.path, + xcresultBundle.basename, + ], workingDir: resultBundleTemp); } else { print( - 'xcresult bundle ${xcresultBundle.path} does not exist, skipping upload'); + 'xcresult bundle ${xcresultBundle.path} does not exist, skipping upload', + ); } } } @@ -116,36 +116,34 @@ class Xcode { /// contains a target called [target], false if it does not, and null if the /// check fails (e.g., if [project] is not an Xcode project). Future projectHasTarget(Directory project, String target) async { - final io.ProcessResult result = - await processRunner.run(_xcRunCommand, [ - _xcodeBuildCommand, - '-list', - '-json', - '-project', - project.path, - ]); + final io.ProcessResult result = await processRunner.run( + _xcRunCommand, + [_xcodeBuildCommand, '-list', '-json', '-project', project.path], + ); if (result.exitCode != 0) { return null; } Map? projectInfo; try { - projectInfo = (jsonDecode(result.stdout as String) - as Map)['project'] as Map?; + projectInfo = + (jsonDecode(result.stdout as String) + as Map)['project'] + as Map?; } on FormatException { return null; } if (projectInfo == null) { return null; } - final List? targets = - (projectInfo['targets'] as List?)?.cast(); + final List? targets = (projectInfo['targets'] as List?) + ?.cast(); return targets?.contains(target) ?? false; } /// Returns the newest available simulator (highest OS version, with ties /// broken in favor of newest device), if any. Future findBestAvailableIphoneSimulator() async { - final List findSimulatorsArguments = [ + final findSimulatorsArguments = [ 'simctl', 'list', 'devices', @@ -153,23 +151,26 @@ class Xcode { 'available', '--json', ]; - final String findSimulatorCompleteCommand = + final findSimulatorCompleteCommand = '$_xcRunCommand ${findSimulatorsArguments.join(' ')}'; if (log) { print('Looking for available simulators...'); print(findSimulatorCompleteCommand); } - final io.ProcessResult findSimulatorsResult = - await processRunner.run(_xcRunCommand, findSimulatorsArguments); + final io.ProcessResult findSimulatorsResult = await processRunner.run( + _xcRunCommand, + findSimulatorsArguments, + ); if (findSimulatorsResult.exitCode != 0) { if (log) { printError( - 'Error occurred while running "$findSimulatorCompleteCommand":\n' - '${findSimulatorsResult.stderr}'); + 'Error occurred while running "$findSimulatorCompleteCommand":\n' + '${findSimulatorsResult.stderr}', + ); } return null; } - final Map simulatorListJson = + final simulatorListJson = jsonDecode(findSimulatorsResult.stdout as String) as Map; final List> runtimes = @@ -184,12 +185,12 @@ class Xcode { String? id; // Looking for runtimes, trying to find one with highest OS version. for (final Map rawRuntimeMap in runtimes.reversed) { - final Map runtimeMap = - rawRuntimeMap.cast(); + final Map runtimeMap = rawRuntimeMap + .cast(); if ((runtimeMap['name'] as String?)?.contains('iOS') != true) { continue; } - final String? runtimeID = runtimeMap['identifier'] as String?; + final runtimeID = runtimeMap['identifier'] as String?; if (runtimeID == null) { continue; } @@ -225,8 +226,9 @@ class Xcode { Directory macOSDirectory, String configuration, ) { - final String entitlementDefaultFileName = - configuration == 'Release' ? 'Release' : 'DebugProfile'; + final entitlementDefaultFileName = configuration == 'Release' + ? 'Release' + : 'DebugProfile'; final File entitlementFile = macOSDirectory .childDirectory('Runner') @@ -237,18 +239,21 @@ class Xcode { return null; } - final String originalEntitlementFileContents = - entitlementFile.readAsStringSync(); + final String originalEntitlementFileContents = entitlementFile + .readAsStringSync(); final File disabledSandboxEntitlementFile = macOSDirectory - .fileSystem.systemTempDirectory + .fileSystem + .systemTempDirectory .createTempSync('flutter_disable_sandbox_entitlement.') .childFile( - '${entitlementDefaultFileName}WithDisabledSandboxing.entitlements'); + '${entitlementDefaultFileName}WithDisabledSandboxing.entitlements', + ); disabledSandboxEntitlementFile.createSync(recursive: true); disabledSandboxEntitlementFile.writeAsStringSync( originalEntitlementFileContents.replaceAll( RegExp( - r'com\.apple\.security\.app-sandbox<\/key>[\S\s]*?'), + r'com\.apple\.security\.app-sandbox<\/key>[\S\s]*?', + ), ''' com.apple.security.app-sandbox ''', diff --git a/script/tool/lib/src/create_all_packages_app_command.dart b/script/tool/lib/src/create_all_packages_app_command.dart index 2afdd82d1dc4..e766b0810607 100644 --- a/script/tool/lib/src/create_all_packages_app_command.dart +++ b/script/tool/lib/src/create_all_packages_app_command.dart @@ -34,18 +34,24 @@ class CreateAllPackagesAppCommand extends PackageCommand { ProcessRunner processRunner = const ProcessRunner(), Platform platform = const LocalPlatform(), }) : super(packagesDir, processRunner: processRunner, platform: platform) { - argParser.addOption(_outputDirectoryFlag, - defaultsTo: packagesDir.parent.path, - help: 'The path the directory to create the "$allPackagesProjectName" ' - 'project in.\n' - 'Defaults to the repository root.'); - argParser.addOption(_legacySourceFlag, - help: 'A partial project directory to use as a source for replacing ' - 'portions of the created app. All top-level directories in the ' - 'source will replace the corresponding directories in the output ' - 'directory post-create.\n\n' - 'The replacement will be done before any tool-driven ' - 'modifications.'); + argParser.addOption( + _outputDirectoryFlag, + defaultsTo: packagesDir.parent.path, + help: + 'The path the directory to create the "$allPackagesProjectName" ' + 'project in.\n' + 'Defaults to the repository root.', + ); + argParser.addOption( + _legacySourceFlag, + help: + 'A partial project directory to use as a source for replacing ' + 'portions of the created app. All top-level directories in the ' + 'source will replace the corresponding directories in the output ' + 'directory post-create.\n\n' + 'The replacement will be done before any tool-driven ' + 'modifications.', + ); } static const String _legacySourceFlag = 'legacy-source'; @@ -76,15 +82,16 @@ class CreateAllPackagesAppCommand extends PackageCommand { final String? legacySource = getNullableStringArg(_legacySourceFlag); if (legacySource != null) { - final Directory legacyDir = - packagesDir.fileSystem.directory(legacySource); + final Directory legacyDir = packagesDir.fileSystem.directory( + legacySource, + ); await _replaceWithLegacy(target: _appDirectory, source: legacyDir); } final Set excluded = getExcludedPackageNames(); if (excluded.isNotEmpty) { print('Exluding the following plugins from the combined build:'); - for (final String plugin in excluded) { + for (final plugin in excluded) { print(' $plugin'); } print(''); @@ -100,7 +107,8 @@ class CreateAllPackagesAppCommand extends PackageCommand { if (!platform.isWindows) { if (!await runPubGet(app, processRunner, platform)) { printError( - "Failed to generate native build files via 'flutter pub get'"); + "Failed to generate native build files via 'flutter pub get'", + ); throw ToolExit(_exitGenNativeBuildFilesFailed); } } @@ -116,19 +124,18 @@ class CreateAllPackagesAppCommand extends PackageCommand { } Future _createApp() async { - return processRunner.runAndStream( - flutterCommand, - [ - 'create', - '--template=app', - '--project-name=$allPackagesProjectName', - _appDirectory.path, - ], - ); + return processRunner.runAndStream(flutterCommand, [ + 'create', + '--template=app', + '--project-name=$allPackagesProjectName', + _appDirectory.path, + ]); } - Future _replaceWithLegacy( - {required Directory target, required Directory source}) async { + Future _replaceWithLegacy({ + required Directory target, + required Directory source, + }) async { if (!source.existsSync()) { printError('No such legacy source directory: ${source.path}'); throw ToolExit(_exitMissingLegacySource); @@ -148,14 +155,19 @@ class CreateAllPackagesAppCommand extends PackageCommand { void _copyDirectory({required Directory target, required Directory source}) { target.createSync(recursive: true); for (final FileSystemEntity entity in source.listSync(recursive: true)) { - final List subcomponents = - p.split(p.relative(entity.path, from: source.path)); + final List subcomponents = p.split( + p.relative(entity.path, from: source.path), + ); if (entity is Directory) { - childDirectoryWithSubcomponents(target, subcomponents) - .createSync(recursive: true); + childDirectoryWithSubcomponents( + target, + subcomponents, + ).createSync(recursive: true); } else if (entity is File) { - final File targetFile = - childFileWithSubcomponents(target, subcomponents); + final File targetFile = childFileWithSubcomponents( + target, + subcomponents, + ); targetFile.parent.createSync(recursive: true); entity.copySync(targetFile.path); } else { @@ -182,7 +194,7 @@ class CreateAllPackagesAppCommand extends PackageCommand { throw ToolExit(_exitMissingFile); } - final StringBuffer output = StringBuffer(); + final output = StringBuffer(); for (final String line in file.readAsLinesSync()) { List? replacementLines; for (final MapEntry> replacement @@ -219,9 +231,7 @@ class CreateAllPackagesAppCommand extends PackageCommand { .childDirectory('app') .listSync() .whereType() - .firstWhere( - (File file) => file.basename.startsWith('build.gradle'), - ); + .firstWhere((File file) => file.basename.startsWith('build.gradle')); final bool gradleFileIsKotlin = gradleFile.basename.endsWith('kts'); @@ -235,12 +245,12 @@ dependencies {} '''); } - final String lifecycleDependency = gradleFileIsKotlin + final lifecycleDependency = gradleFileIsKotlin ? ' implementation("androidx.lifecycle:lifecycle-runtime:2.2.0-rc01")' : " implementation 'androidx.lifecycle:lifecycle-runtime:2.2.0-rc01'"; // Desugaring is required for interactive_media_ads. - final String desugaringDependency = gradleFileIsKotlin + final desugaringDependency = gradleFileIsKotlin ? ' coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")' : " coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'"; @@ -251,7 +261,7 @@ dependencies {} 'compileSdk': ['compileSdk = 36'] else ...>{ 'compileSdkVersion': ['compileSdk 36'], - } + }, }, regexReplacements: >{ // Desugaring is required for interactive_media_ads. @@ -290,25 +300,20 @@ dependencies {} // specific language features via SDK version, so using a different one // can cause compilation failures. final Pubspec originalPubspec = app.parsePubspec(); - const String dartSdkKey = 'sdk'; + const dartSdkKey = 'sdk'; final VersionConstraint dartSdkConstraint = originalPubspec.environment[dartSdkKey] ?? - VersionConstraint.compatibleWith( - Version.parse('3.0.0'), - ); + VersionConstraint.compatibleWith(Version.parse('3.0.0')); final Map pluginDeps = await _getValidPathDependencies(); - final Pubspec pubspec = Pubspec( + final pubspec = Pubspec( allPackagesProjectName, description: 'Flutter app containing all 1st party plugins.', version: Version.parse('1.0.0+1'), - environment: { - dartSdkKey: dartSdkConstraint, - }, - dependencies: { - 'flutter': SdkDependency('flutter'), - }..addAll(pluginDeps), + environment: {dartSdkKey: dartSdkConstraint}, + dependencies: {'flutter': SdkDependency('flutter')} + ..addAll(pluginDeps), devDependencies: { 'flutter_test': SdkDependency('flutter'), }, @@ -332,8 +337,7 @@ dependencies {} } Future> _getValidPathDependencies() async { - final Map pathDependencies = - {}; + final pathDependencies = {}; await for (final PackageEnumerationEntry entry in getTargetPackages()) { final RepositoryPackage package = entry.package; @@ -368,13 +372,13 @@ dev_dependencies:${_pubspecMapString(pubspec.devDependencies)} } String _pubspecMapString(Map values) { - final StringBuffer buffer = StringBuffer(); + final buffer = StringBuffer(); for (final MapEntry entry in values.entries) { buffer.writeln(); final Object? entryValue = entry.value; if (entryValue is VersionConstraint) { - String value = entryValue.toString(); + var value = entryValue.toString(); // Range constraints require quoting. if (value.startsWith('>') || value.startsWith('<')) { value = "'$value'"; @@ -392,8 +396,10 @@ dev_dependencies:${_pubspecMapString(pubspec.devDependencies)} // path.split leaves a \ on drive components that isn't necessary, // and confuses pub, so remove it. if (firstComponent.endsWith(r':\')) { - components[0] = - firstComponent.substring(0, firstComponent.length - 1); + components[0] = firstComponent.substring( + 0, + firstComponent.length - 1, + ); } depPath = p.posix.joinAll(components); } @@ -415,8 +421,9 @@ dev_dependencies:${_pubspecMapString(pubspec.devDependencies)} return; } - final File podfile = - app.platformDirectory(FlutterPlatform.macos).childFile('Podfile'); + final File podfile = app + .platformDirectory(FlutterPlatform.macos) + .childFile('Podfile'); _adjustFile( podfile, replacements: >{ @@ -436,7 +443,7 @@ dev_dependencies:${_pubspecMapString(pubspec.devDependencies)} replacements: >{ // macOS 10.15 is required by in_app_purchase. 'MACOSX_DEPLOYMENT_TARGET': [ - ' MACOSX_DEPLOYMENT_TARGET = 10.15;' + ' MACOSX_DEPLOYMENT_TARGET = 10.15;', ], }, ); @@ -452,7 +459,7 @@ dev_dependencies:${_pubspecMapString(pubspec.devDependencies)} replacements: >{ // iOS 14 is required by google_maps_flutter. 'IPHONEOS_DEPLOYMENT_TARGET': [ - ' IPHONEOS_DEPLOYMENT_TARGET = 14.0;' + ' IPHONEOS_DEPLOYMENT_TARGET = 14.0;', ], }, ); diff --git a/script/tool/lib/src/custom_test_command.dart b/script/tool/lib/src/custom_test_command.dart index e7995dbb0c4d..bed1db101bfc 100644 --- a/script/tool/lib/src/custom_test_command.dart +++ b/script/tool/lib/src/custom_test_command.dart @@ -31,30 +31,36 @@ class CustomTestCommand extends PackageLoopingCommand { List get aliases => ['test-custom']; @override - final String description = 'Runs package-specific custom tests defined in ' + final String description = + 'Runs package-specific custom tests defined in ' "a package's custom test script.\n\n" 'This command requires "dart" to be in your path.'; @override Future runForPackage(RepositoryPackage package) async { final File script = package.customTestScript; - final String relativeScriptPath = - getRelativePosixPath(script, from: package.directory); + final String relativeScriptPath = getRelativePosixPath( + script, + from: package.directory, + ); final File legacyScript = package.directory.childFile(_legacyScriptName); String? customSkipReason; - bool ranTests = false; + var ranTests = false; // Run the custom Dart script if presest. if (script.existsSync()) { // Ensure that dependencies are available. if (!await runPubGet(package, processRunner, platform)) { - return PackageResult.fail( - ['Unable to get script dependencies']); + return PackageResult.fail([ + 'Unable to get script dependencies', + ]); } final int testExitCode = await processRunner.runAndStream( - 'dart', ['run', relativeScriptPath], - workingDir: package.directory); + 'dart', + ['run', relativeScriptPath], + workingDir: package.directory, + ); if (testExitCode != 0) { return PackageResult.fail(); } @@ -64,12 +70,15 @@ class CustomTestCommand extends PackageLoopingCommand { // Run the legacy script if present. if (legacyScript.existsSync()) { if (platform.isWindows) { - customSkipReason = '$_legacyScriptName is not supported on Windows. ' + customSkipReason = + '$_legacyScriptName is not supported on Windows. ' 'Please migrate to $relativeScriptPath.'; } else { final int exitCode = await processRunner.runAndStream( - legacyScript.path, [], - workingDir: package.directory); + legacyScript.path, + [], + workingDir: package.directory, + ); if (exitCode != 0) { return PackageResult.fail(); } @@ -79,7 +88,8 @@ class CustomTestCommand extends PackageLoopingCommand { if (!ranTests) { return PackageResult.skip( - customSkipReason ?? 'No $relativeScriptPath file'); + customSkipReason ?? 'No $relativeScriptPath file', + ); } return PackageResult.success(); diff --git a/script/tool/lib/src/dart_test_command.dart b/script/tool/lib/src/dart_test_command.dart index 5b23e76dd5ae..5e67898a7051 100644 --- a/script/tool/lib/src/dart_test_command.dart +++ b/script/tool/lib/src/dart_test_command.dart @@ -40,11 +40,14 @@ class DartTestCommand extends PackageLoopingCommand { ); argParser.addOption( _platformFlag, - help: 'Runs tests on the given platform instead of the default platform ' + help: + 'Runs tests on the given platform instead of the default platform ' '("vm" in most cases, "chrome" for web plugin implementations).', ); - argParser.addFlag(kWebWasmFlag, - help: 'Compile to WebAssembly rather than JavaScript'); + argParser.addFlag( + kWebWasmFlag, + help: 'Compile to WebAssembly rather than JavaScript', + ); } static const String _platformFlag = 'platform'; @@ -59,7 +62,8 @@ class DartTestCommand extends PackageLoopingCommand { List get aliases => ['test', 'test-dart']; @override - final String description = 'Runs the Dart tests for all packages.\n\n' + final String description = + 'Runs the Dart tests for all packages.\n\n' 'This command requires "flutter" to be in your path.'; @override @@ -85,16 +89,20 @@ class DartTestCommand extends PackageLoopingCommand { // federated plugin implementations) on web, since there's no reason to // expect them to work. final bool webPlatform = platform != null && platform != 'vm'; - final bool explicitVMPlatform = platform == 'vm'; - final bool isWebOnlyPluginImplementation = pluginSupportsPlatform( - platformWeb, package, - requiredMode: PlatformSupport.inline) && + final explicitVMPlatform = platform == 'vm'; + final bool isWebOnlyPluginImplementation = + pluginSupportsPlatform( + platformWeb, + package, + requiredMode: PlatformSupport.inline, + ) && package.directory.basename.endsWith('_web'); if (webPlatform) { if (isFlutterPlugin(package) && !pluginSupportsPlatform(platformWeb, package)) { return PackageResult.skip( - "Non-web plugin tests don't need web testing."); + "Non-web plugin tests don't need web testing.", + ); } if (_testOnTarget(package) == _TestPlatform.vm) { // This explict skip is necessary because trying to run tests in a mode @@ -132,8 +140,11 @@ class DartTestCommand extends PackageLoopingCommand { } /// Runs the Dart tests for a Flutter package, returning true on success. - Future _runFlutterTests(RepositoryPackage package, - {String? platform, bool wasm = false}) async { + Future _runFlutterTests( + RepositoryPackage package, { + String? platform, + bool wasm = false, + }) async { final String experiment = getStringArg(kEnableExperiment); final int exitCode = await processRunner.runAndStream( @@ -153,8 +164,11 @@ class DartTestCommand extends PackageLoopingCommand { } /// Runs the Dart tests for a non-Flutter package, returning true on success. - Future _runDartTests(RepositoryPackage package, - {String? platform, bool wasm = false}) async { + Future _runDartTests( + RepositoryPackage package, { + String? platform, + bool wasm = false, + }) async { // Unlike `flutter test`, `dart run test` does not automatically get // packages if (!await runPubGet(package, processRunner, super.platform)) { @@ -164,17 +178,13 @@ class DartTestCommand extends PackageLoopingCommand { final String experiment = getStringArg(kEnableExperiment); - final int exitCode = await processRunner.runAndStream( - 'dart', - [ - 'run', - if (experiment.isNotEmpty) '--enable-experiment=$experiment', - 'test', - if (platform != null) '--platform=$platform', - if (wasm) '--compiler=dart2wasm', - ], - workingDir: package.directory, - ); + final int exitCode = await processRunner.runAndStream('dart', [ + 'run', + if (experiment.isNotEmpty) '--enable-experiment=$experiment', + 'test', + if (platform != null) '--platform=$platform', + if (wasm) '--compiler=dart2wasm', + ], workingDir: package.directory); return exitCode == 0; } @@ -187,7 +197,7 @@ class DartTestCommand extends PackageLoopingCommand { if (!testConfig.existsSync()) { return null; } - final RegExp testOnRegex = RegExp(r'^test_on:\s*([a-z].*[a-z])\s*$'); + final testOnRegex = RegExp(r'^test_on:\s*([a-z].*[a-z])\s*$'); for (final String line in testConfig.readAsLinesSync()) { final RegExpMatch? match = testOnRegex.firstMatch(line); if (match != null) { @@ -204,10 +214,12 @@ class DartTestCommand extends PackageLoopingCommand { case 'browser': return _TestPlatform.browser; default: - printError('Unknown "test_on" value: "$targetFilter"\n' - "If this value needs to be supported for this package's tests, " - 'please update the repository tooling to support more test_on ' - 'modes.'); + printError( + 'Unknown "test_on" value: "$targetFilter"\n' + "If this value needs to be supported for this package's tests, " + 'please update the repository tooling to support more test_on ' + 'modes.', + ); throw ToolExit(_exitUnknownTestPlatform); } } diff --git a/script/tool/lib/src/dependabot_check_command.dart b/script/tool/lib/src/dependabot_check_command.dart index d92b906b180d..6ac09e56f2da 100644 --- a/script/tool/lib/src/dependabot_check_command.dart +++ b/script/tool/lib/src/dependabot_check_command.dart @@ -13,9 +13,11 @@ import 'common/repository_package.dart'; class DependabotCheckCommand extends PackageLoopingCommand { /// Creates Dependabot check command instance. DependabotCheckCommand(super.packagesDir, {super.gitDir}) { - argParser.addOption(_configPathFlag, - help: 'Path to the Dependabot configuration file', - defaultsTo: '.github/dependabot.yml'); + argParser.addOption( + _configPathFlag, + help: 'Path to the Dependabot configuration file', + defaultsTo: '.github/dependabot.yml', + ); } static const String _configPathFlag = 'config'; @@ -46,22 +48,27 @@ class DependabotCheckCommand extends PackageLoopingCommand { Future initializeRun() async { _repoRoot = packagesDir.fileSystem.directory((await gitDir).path); - final YamlMap config = loadYaml(_repoRoot - .childFile(getStringArg(_configPathFlag)) - .readAsStringSync()) as YamlMap; + final config = + loadYaml( + _repoRoot + .childFile(getStringArg(_configPathFlag)) + .readAsStringSync(), + ) + as YamlMap; final dynamic entries = config['updates']; if (entries is! YamlList) { return; } - const String typeKey = 'package-ecosystem'; - const String dirKey = 'directory'; - const String dirsKey = 'directories'; - final Iterable gradleEntries = entries - .cast() - .where((YamlMap entry) => entry[typeKey] == 'gradle'); - final Iterable directoryEntries = - gradleEntries.map((YamlMap entry) => entry[dirKey] as String?); + const typeKey = 'package-ecosystem'; + const dirKey = 'directory'; + const dirsKey = 'directories'; + final Iterable gradleEntries = entries.cast().where( + (YamlMap entry) => entry[typeKey] == 'gradle', + ); + final Iterable directoryEntries = gradleEntries.map( + (YamlMap entry) => entry[dirKey] as String?, + ); final Iterable directoriesEntries = gradleEntries .map((YamlMap entry) => entry[dirsKey] as YamlList?) .expand((YamlList? list) => list?.nodes ?? []) @@ -75,16 +82,18 @@ class DependabotCheckCommand extends PackageLoopingCommand { @override Future runForPackage(RepositoryPackage package) async { - bool skipped = true; - final List errors = []; + var skipped = true; + final errors = []; final _GradleCoverageResult gradleResult = _validateDependabotGradleCoverage(package); skipped = skipped && gradleResult.runState == RunState.skipped; if (gradleResult.runState == RunState.failed) { printError('${indentation}Missing Gradle coverage.'); - print('${indentation}Add a "gradle" entry to ' - '${getStringArg(_configPathFlag)} for ${gradleResult.missingPath}'); + print( + '${indentation}Add a "gradle" entry to ' + '${getStringArg(_configPathFlag)} for ${gradleResult.missingPath}', + ); errors.add('Missing Gradle coverage'); } @@ -104,20 +113,22 @@ class DependabotCheckCommand extends PackageLoopingCommand { /// - failed if it includes gradle and is not covered. /// - skipped if it doesn't include gradle. _GradleCoverageResult _validateDependabotGradleCoverage( - RepositoryPackage package) { - final Directory androidDir = - package.platformDirectory(FlutterPlatform.android); + RepositoryPackage package, + ) { + final Directory androidDir = package.platformDirectory( + FlutterPlatform.android, + ); final Directory appDir = androidDir.childDirectory('app'); if (appDir.existsSync()) { // It's an app, so only check for the app directory to be covered. - final String dependabotPath = + final dependabotPath = '/${getRelativePosixPath(appDir, from: _repoRoot)}'; return _gradleDirs.contains(dependabotPath) ? _GradleCoverageResult(RunState.succeeded) : _GradleCoverageResult(RunState.failed, missingPath: dependabotPath); } else if (androidDir.existsSync()) { // It's a library, so only check for the android directory to be covered. - final String dependabotPath = + final dependabotPath = '/${getRelativePosixPath(androidDir, from: _repoRoot)}'; return _gradleDirs.contains(dependabotPath) ? _GradleCoverageResult(RunState.succeeded) diff --git a/script/tool/lib/src/drive_examples_command.dart b/script/tool/lib/src/drive_examples_command.dart index 56250523ccea..5609e04413a8 100644 --- a/script/tool/lib/src/drive_examples_command.dart +++ b/script/tool/lib/src/drive_examples_command.dart @@ -30,30 +30,47 @@ class DriveExamplesCommand extends PackageLoopingCommand { super.platform, super.gitDir, }) { - argParser.addFlag(platformAndroid, - help: 'Runs the Android implementation of the examples', - aliases: const [platformAndroidAlias]); - argParser.addFlag(platformIOS, - help: 'Runs the iOS implementation of the examples'); - argParser.addFlag(platformLinux, - help: 'Runs the Linux implementation of the examples'); - argParser.addFlag(platformMacOS, - help: 'Runs the macOS implementation of the examples'); - argParser.addFlag(platformWeb, - help: 'Runs the web implementation of the examples'); - argParser.addFlag(platformWindows, - help: 'Runs the Windows implementation of the examples'); - argParser.addFlag(kWebWasmFlag, - help: 'Compile to WebAssembly rather than JavaScript'); + argParser.addFlag( + platformAndroid, + help: 'Runs the Android implementation of the examples', + aliases: const [platformAndroidAlias], + ); + argParser.addFlag( + platformIOS, + help: 'Runs the iOS implementation of the examples', + ); + argParser.addFlag( + platformLinux, + help: 'Runs the Linux implementation of the examples', + ); + argParser.addFlag( + platformMacOS, + help: 'Runs the macOS implementation of the examples', + ); + argParser.addFlag( + platformWeb, + help: 'Runs the web implementation of the examples', + ); + argParser.addFlag( + platformWindows, + help: 'Runs the Windows implementation of the examples', + ); + argParser.addFlag( + kWebWasmFlag, + help: 'Compile to WebAssembly rather than JavaScript', + ); argParser.addOption( kEnableExperiment, defaultsTo: '', help: 'Runs the driver tests in Dart VM with the given experiments enabled.', ); - argParser.addFlag(_chromeDriverFlag, - help: 'Runs chromedriver for the duration of the test.\n\n' - 'Requires the correct version of chromedriver to be in your path.'); + argParser.addFlag( + _chromeDriverFlag, + help: + 'Runs chromedriver for the duration of the test.\n\n' + 'Requires the correct version of chromedriver to be in your path.', + ); } static const String _chromeDriverFlag = 'run-chromedriver'; @@ -62,7 +79,8 @@ class DriveExamplesCommand extends PackageLoopingCommand { final String name = 'drive-examples'; @override - final String description = 'Runs Dart integration tests for example apps.\n\n' + final String description = + 'Runs Dart integration tests for example apps.\n\n' "This runs all tests in each example's integration_test directory, " 'via "flutter test" on most platforms, and "flutter drive" on web.\n\n' 'This command requires "flutter" to be in your path.'; @@ -82,7 +100,7 @@ class DriveExamplesCommand extends PackageLoopingCommand { @override Future initializeRun() async { - final List platformSwitches = [ + final platformSwitches = [ platformAndroid, platformIOS, platformLinux, @@ -98,8 +116,9 @@ class DriveExamplesCommand extends PackageLoopingCommand { // If that is implemented, this check can be relaxed. if (platformCount != 1) { printError( - 'Exactly one of ${platformSwitches.map((String platform) => '--$platform').join(', ')} ' - 'must be specified.'); + 'Exactly one of ${platformSwitches.map((String platform) => '--$platform').join(', ')} ' + 'must be specified.', + ); throw ToolExit(_exitInvalidArgs); } @@ -159,7 +178,8 @@ class DriveExamplesCommand extends PackageLoopingCommand { // Platform interface packages generally aren't intended to have // examples, and don't need integration tests, so skip rather than fail. return PackageResult.skip( - 'Platform interfaces are not expected to have integration tests.'); + 'Platform interfaces are not expected to have integration tests.', + ); } // For plugin packages, skip if the plugin itself doesn't support any @@ -167,30 +187,35 @@ class DriveExamplesCommand extends PackageLoopingCommand { if (isPlugin) { final Iterable requestedPlatforms = _targetDeviceFlags.keys; final Iterable unsupportedPlatforms = requestedPlatforms.where( - (String platform) => !pluginSupportsPlatform(platform, package)); - for (final String platform in unsupportedPlatforms) { + (String platform) => !pluginSupportsPlatform(platform, package), + ); + for (final platform in unsupportedPlatforms) { print('Skipping unsupported platform $platform...'); } if (unsupportedPlatforms.length == requestedPlatforms.length) { return PackageResult.skip( - '${package.displayName} does not support any requested platform.'); + '${package.displayName} does not support any requested platform.', + ); } } - int examplesFound = 0; - int supportedExamplesFound = 0; - bool testsRan = false; - final List errors = []; + var examplesFound = 0; + var supportedExamplesFound = 0; + var testsRan = false; + final errors = []; for (final RepositoryPackage example in package.getExamples()) { ++examplesFound; - final String exampleName = - getRelativePosixPath(example.directory, from: packagesDir); + final String exampleName = getRelativePosixPath( + example.directory, + from: packagesDir, + ); // Skip examples that don't support any requested platform(s). final List deviceFlags = _deviceFlagsForExample(example); if (deviceFlags.isEmpty) { print( - 'Skipping $exampleName; does not support any requested platforms.'); + 'Skipping $exampleName; does not support any requested platforms.', + ); continue; } @@ -203,13 +228,13 @@ class DriveExamplesCommand extends PackageLoopingCommand { } // Check files for known problematic patterns. - testTargets - .where((File file) => !_validateIntegrationTest(file)) - .forEach((File file) { - // Report the issue, but continue with the test as the validation - // errors don't prevent running. - errors.add('${file.basename} failed validation'); - }); + testTargets.where((File file) => !_validateIntegrationTest(file)).forEach( + (File file) { + // Report the issue, but continue with the test as the validation + // errors don't prevent running. + errors.add('${file.basename} failed validation'); + }, + ); // `flutter test` doesn't yet support web integration tests, so fall back // to `flutter drive`. @@ -231,10 +256,11 @@ class DriveExamplesCommand extends PackageLoopingCommand { Process? chromedriver; if (getBoolArg(_chromeDriverFlag)) { print('Starting chromedriver on port $_chromeDriverPort'); - chromedriver = await processRunner - .start('chromedriver', ['--port=$_chromeDriverPort']); + chromedriver = await processRunner.start('chromedriver', [ + '--port=$_chromeDriverPort', + ]); } - for (final File driver in drivers) { + for (final driver in drivers) { final List failingTargets = await _driveTests( example, driver, @@ -242,9 +268,10 @@ class DriveExamplesCommand extends PackageLoopingCommand { deviceFlags: deviceFlags, exampleName: exampleName, ); - for (final File failingTarget in failingTargets) { + for (final failingTarget in failingTargets) { errors.add( - getRelativePosixPath(failingTarget, from: package.directory)); + getRelativePosixPath(failingTarget, from: package.directory), + ); } } if (chromedriver != null) { @@ -252,8 +279,11 @@ class DriveExamplesCommand extends PackageLoopingCommand { chromedriver.kill(); } } else { - if (!await _runTests(example, - deviceFlags: deviceFlags, testFiles: testTargets)) { + if (!await _runTests( + example, + deviceFlags: deviceFlags, + testFiles: testTargets, + )) { errors.add('Integration tests failed.'); } } @@ -263,12 +293,15 @@ class DriveExamplesCommand extends PackageLoopingCommand { // is the only way to test the method channel communication. if (isPlugin) { printError( - 'No driver tests were run ($examplesFound example(s) found).'); + 'No driver tests were run ($examplesFound example(s) found).', + ); errors.add('No tests ran (use --exclude if this is intentional).'); } else { - return PackageResult.skip(supportedExamplesFound == 0 - ? 'No example supports requested platform(s).' - : 'No example is configured for integration tests.'); + return PackageResult.skip( + supportedExamplesFound == 0 + ? 'No example supports requested platform(s).' + : 'No example is configured for integration tests.', + ); } } return errors.isEmpty @@ -279,15 +312,17 @@ class DriveExamplesCommand extends PackageLoopingCommand { /// Returns the device flags for the intersection of the requested platforms /// and the platforms supported by [example]. List _deviceFlagsForExample(RepositoryPackage example) { - final List deviceFlags = []; + final deviceFlags = []; for (final MapEntry> entry in _targetDeviceFlags.entries) { final String platform = entry.key; if (example.appSupportsPlatform(getPlatformByName(platform))) { deviceFlags.addAll(entry.value); } else { - final String exampleName = - getRelativePosixPath(example.directory, from: packagesDir); + final String exampleName = getRelativePosixPath( + example.directory, + from: packagesDir, + ); print('Skipping unsupported platform $platform for $exampleName'); } } @@ -295,16 +330,18 @@ class DriveExamplesCommand extends PackageLoopingCommand { } Future> _getDevicesForPlatform(String platform) async { - final List deviceIds = []; + final deviceIds = []; final ProcessResult result = await processRunner.run( - flutterCommand, ['devices', '--machine'], - stdoutEncoding: utf8); + flutterCommand, + ['devices', '--machine'], + stdoutEncoding: utf8, + ); if (result.exitCode != 0) { return deviceIds; } - String output = result.stdout as String; + var output = result.stdout as String; // --machine doesn't currently prevent the tool from printing banners; // see https://github.com/flutter/flutter/issues/86055. This workaround // can be removed once that is fixed. @@ -312,11 +349,11 @@ class DriveExamplesCommand extends PackageLoopingCommand { final List> devices = (jsonDecode(output) as List).cast>(); - for (final Map deviceInfo in devices) { + for (final deviceInfo in devices) { final String targetPlatform = (deviceInfo['targetPlatform'] as String?) ?? ''; if (targetPlatform.startsWith(platform)) { - final String? deviceId = deviceInfo['id'] as String?; + final deviceId = deviceInfo['id'] as String?; if (deviceId != null) { deviceIds.add(deviceId); } @@ -326,7 +363,7 @@ class DriveExamplesCommand extends PackageLoopingCommand { } Future> _getDrivers(RepositoryPackage example) async { - final List drivers = []; + final drivers = []; final Directory driverDir = example.directory.childDirectory('test_driver'); if (driverDir.existsSync()) { @@ -340,13 +377,15 @@ class DriveExamplesCommand extends PackageLoopingCommand { } Future> _getIntegrationTests(RepositoryPackage example) async { - final List tests = []; - final Directory integrationTestDir = - example.directory.childDirectory('integration_test'); + final tests = []; + final Directory integrationTestDir = example.directory.childDirectory( + 'integration_test', + ); if (integrationTestDir.existsSync()) { - await for (final FileSystemEntity file - in integrationTestDir.list(recursive: true)) { + await for (final FileSystemEntity file in integrationTestDir.list( + recursive: true, + )) { if (file is File && file.basename.endsWith('_test.dart')) { tests.add(file); } @@ -362,12 +401,13 @@ class DriveExamplesCommand extends PackageLoopingCommand { bool _validateIntegrationTest(File testFile) { final List lines = testFile.readAsLinesSync(); - final RegExp badTestPattern = RegExp(r'\s*test\('); + final badTestPattern = RegExp(r'\s*test\('); if (lines.any((String line) => line.startsWith(badTestPattern))) { final String filename = testFile.basename; printError( - '$filename uses "test", which will not report failures correctly. ' - 'Use testWidgets instead.'); + '$filename uses "test", which will not report failures correctly. ' + 'Use testWidgets instead.', + ); return false; } @@ -390,19 +430,19 @@ class DriveExamplesCommand extends PackageLoopingCommand { required List deviceFlags, required String exampleName, }) async { - final List failures = []; + final failures = []; final String enableExperiment = getStringArg(kEnableExperiment); - final String screenshotBasename = + final screenshotBasename = '${exampleName.replaceAll(platform.pathSeparator, '_')}-drive'; - final Directory? screenshotDirectory = - ciLogsDirectory(platform, driver.fileSystem) - ?.childDirectory(screenshotBasename); - - for (final File target in targets) { - final int exitCode = await processRunner.runAndStream( - flutterCommand, - [ + final Directory? screenshotDirectory = ciLogsDirectory( + platform, + driver.fileSystem, + )?.childDirectory(screenshotBasename); + + for (final target in targets) { + final int exitCode = await processRunner + .runAndStream(flutterCommand, [ 'drive', ...deviceFlags, if (enableExperiment.isNotEmpty) @@ -413,8 +453,7 @@ class DriveExamplesCommand extends PackageLoopingCommand { getRelativePosixPath(driver, from: example.directory), '--target', getRelativePosixPath(target, from: example.directory), - ], - workingDir: example.directory); + ], workingDir: example.directory); if (exitCode != 0) { failures.add(target); } @@ -436,51 +475,49 @@ class DriveExamplesCommand extends PackageLoopingCommand { required List testFiles, }) async { final String enableExperiment = getStringArg(kEnableExperiment); - final Directory? logsDirectory = - ciLogsDirectory(platform, testFiles.first.fileSystem); + final Directory? logsDirectory = ciLogsDirectory( + platform, + testFiles.first.fileSystem, + ); // Workaround for https://github.com/flutter/flutter/issues/135673 // Once that is fixed on stable, this logic can be removed and the command // can always just be run with "integration_test". - final bool needsMultipleInvocations = testFiles.length > 1 && + final bool needsMultipleInvocations = + testFiles.length > 1 && (getBoolArg(platformLinux) || getBoolArg(platformMacOS) || getBoolArg(platformWindows)); final Iterable individualRunTargets = needsMultipleInvocations - ? testFiles - .map((File f) => getRelativePosixPath(f, from: example.directory)) + ? testFiles.map( + (File f) => getRelativePosixPath(f, from: example.directory), + ) : ['integration_test']; - bool passed = true; - for (final String target in individualRunTargets) { - final Timer timeoutTimer = Timer(const Duration(minutes: 10), () async { - final String screenshotBasename = + var passed = true; + for (final target in individualRunTargets) { + final timeoutTimer = Timer(const Duration(minutes: 10), () async { + final screenshotBasename = 'test-timeout-screenshot_${target.replaceAll(platform.pathSeparator, '_')}.png'; printWarning( - 'Test is taking a long time, taking screenshot $screenshotBasename...'); - await processRunner.runAndStream( - flutterCommand, - [ - 'screenshot', - ...deviceFlags, - if (logsDirectory != null) - '--out=${logsDirectory.childFile(screenshotBasename).path}', - ], - workingDir: example.directory, + 'Test is taking a long time, taking screenshot $screenshotBasename...', ); - }); - final int exitCode = await processRunner.runAndStream( - flutterCommand, - [ - 'test', + await processRunner.runAndStream(flutterCommand, [ + 'screenshot', ...deviceFlags, - if (enableExperiment.isNotEmpty) - '--enable-experiment=$enableExperiment', - if (logsDirectory != null) '--debug-logs-dir=${logsDirectory.path}', - target, - ], - workingDir: example.directory, - ); + if (logsDirectory != null) + '--out=${logsDirectory.childFile(screenshotBasename).path}', + ], workingDir: example.directory); + }); + final int exitCode = await processRunner + .runAndStream(flutterCommand, [ + 'test', + ...deviceFlags, + if (enableExperiment.isNotEmpty) + '--enable-experiment=$enableExperiment', + if (logsDirectory != null) '--debug-logs-dir=${logsDirectory.path}', + target, + ], workingDir: example.directory); timeoutTimer.cancel(); passed = passed && (exitCode == 0); diff --git a/script/tool/lib/src/federation_safety_check_command.dart b/script/tool/lib/src/federation_safety_check_command.dart index 059c4393b739..40bf8b6e6a46 100644 --- a/script/tool/lib/src/federation_safety_check_command.dart +++ b/script/tool/lib/src/federation_safety_check_command.dart @@ -67,8 +67,9 @@ class FederationSafetyCheckCommand extends PackageLoopingCommand { if (packageIndex == -1) { continue; } - final List relativeComponents = - allComponents.sublist(packageIndex + 1); + final List relativeComponents = allComponents.sublist( + packageIndex + 1, + ); // The package name is either the directory directly under packages/, or // the directory under that in the case of a federated plugin. String packageName = relativeComponents.removeAt(0); @@ -83,8 +84,9 @@ class FederationSafetyCheckCommand extends PackageLoopingCommand { if (relativeComponents.last.endsWith('.dart') && !await _changeIsCommentOnly(gitVersionFinder, path)) { _changedDartFiles[packageName] ??= []; - _changedDartFiles[packageName]! - .add(p.posix.joinAll(relativeComponents)); + _changedDartFiles[packageName]!.add( + p.posix.joinAll(relativeComponents), + ); } if (packageName.endsWith(_platformInterfaceSuffix) && @@ -109,7 +111,8 @@ class FederationSafetyCheckCommand extends PackageLoopingCommand { // As the leaf nodes in the graph, a published package interface change is // assumed to be correct, and other changes are validated against that. return PackageResult.skip( - 'Platform interface changes are not validated.'); + 'Platform interface changes are not validated.', + ); } // Special-case combination PRs that are following repo process, so that @@ -117,31 +120,35 @@ class FederationSafetyCheckCommand extends PackageLoopingCommand { // the PR (but is still an error so that the PR can't land without following // the resolution process). if (package.getExamples().any(_hasTemporaryDependencyOverrides)) { - printError('"$kDoNotLandWarning" found in pubspec.yaml, so this is ' - 'assumed to be the initial combination PR for a federated change, ' - 'following the standard repository procedure. This failure is ' - 'expected, in order to prevent accidentally landing the temporary ' - 'overrides, and will automatically be resolved when the temporary ' - 'overrides are replaced by dependency version bumps later in the ' - 'process.'); + printError( + '"$kDoNotLandWarning" found in pubspec.yaml, so this is ' + 'assumed to be the initial combination PR for a federated change, ' + 'following the standard repository procedure. This failure is ' + 'expected, in order to prevent accidentally landing the temporary ' + 'overrides, and will automatically be resolved when the temporary ' + 'overrides are replaced by dependency version bumps later in the ' + 'process.', + ); return PackageResult.fail(['Unresolved combo PR.']); } // Uses basename to match _changedPackageFiles. final String basePackageName = package.directory.parent.basename; - final String platformInterfacePackageName = + final platformInterfacePackageName = '$basePackageName$_platformInterfaceSuffix'; final List changedPlatformInterfaceFiles = _changedDartFiles[platformInterfacePackageName] ?? []; - if (!_modifiedAndPublishedPlatformInterfacePackages - .contains(platformInterfacePackageName)) { + if (!_modifiedAndPublishedPlatformInterfacePackages.contains( + platformInterfacePackageName, + )) { print('No published changes for $platformInterfacePackageName.'); return PackageResult.success(); } - if (!changedPlatformInterfaceFiles - .any((String path) => path.startsWith('lib/'))) { + if (!changedPlatformInterfaceFiles.any( + (String path) => path.startsWith('lib/'), + )) { print('No public code changes for $platformInterfacePackageName.'); return PackageResult.success(); } @@ -168,39 +175,48 @@ class FederationSafetyCheckCommand extends PackageLoopingCommand { // change to another file accidentally included), while not setting too // high a bar for detecting mass changes. This can be tuned if there are // issues with false positives or false negatives. - const int massChangePluginThreshold = 3; + const massChangePluginThreshold = 3; if (_changedPlugins.length >= massChangePluginThreshold) { - logWarning('Ignoring potentially dangerous change, as this appears ' - 'to be a mass change.'); + logWarning( + 'Ignoring potentially dangerous change, as this appears ' + 'to be a mass change.', + ); return PackageResult.success(); } - printError('Dart changes are not allowed to other packages in ' - '$basePackageName in the same PR as changes to public Dart code in ' - '$platformInterfacePackageName, as this can cause accidental breaking ' - 'changes to be missed by automated checks. Please split the changes to ' - 'these two packages into separate PRs.\n\n' - 'If you believe that this is a false positive, please file a bug.'); - return PackageResult.fail( - ['$platformInterfacePackageName changed.']); + printError( + 'Dart changes are not allowed to other packages in ' + '$basePackageName in the same PR as changes to public Dart code in ' + '$platformInterfacePackageName, as this can cause accidental breaking ' + 'changes to be missed by automated checks. Please split the changes to ' + 'these two packages into separate PRs.\n\n' + 'If you believe that this is a false positive, please file a bug.', + ); + return PackageResult.fail([ + '$platformInterfacePackageName changed.', + ]); } Future _packageWillBePublished( - String pubspecRepoRelativePosixPath) async { + String pubspecRepoRelativePosixPath, + ) async { final File pubspecFile = childFileWithSubcomponents( - packagesDir.parent, p.posix.split(pubspecRepoRelativePosixPath)); + packagesDir.parent, + p.posix.split(pubspecRepoRelativePosixPath), + ); if (!pubspecFile.existsSync()) { // If the package was deleted, nothing will be published. return false; } - final Pubspec pubspec = Pubspec.parse(pubspecFile.readAsStringSync()); + final pubspec = Pubspec.parse(pubspecFile.readAsStringSync()); if (pubspec.publishTo == 'none') { return false; } final GitVersionFinder gitVersionFinder = await retrieveVersionFinder(); - final Version? previousVersion = - await gitVersionFinder.getPackageVersion(pubspecRepoRelativePosixPath); + final Version? previousVersion = await gitVersionFinder.getPackageVersion( + pubspecRepoRelativePosixPath, + ); if (previousVersion == null) { // The plugin is new, so it will be published. return true; @@ -209,15 +225,17 @@ class FederationSafetyCheckCommand extends PackageLoopingCommand { } Future _changeIsCommentOnly( - GitVersionFinder git, String repoPath) async { + GitVersionFinder git, + String repoPath, + ) async { final List diff = await git.getDiffContents(targetPath: repoPath); - final RegExp changeLine = RegExp(r'^[+-]'); + final changeLine = RegExp(r'^[+-]'); // This will not catch /**/-style comments, but false negatives are fine // (and in practice, we almost never use that comment style in Dart code). - final RegExp commentLine = RegExp(r'^[+-]\s*//'); - final RegExp blankLine = RegExp(r'^[+-]\s*$'); - bool foundComment = false; - for (final String line in diff) { + final commentLine = RegExp(r'^[+-]\s*//'); + final blankLine = RegExp(r'^[+-]\s*$'); + var foundComment = false; + for (final line in diff) { if (!changeLine.hasMatch(line) || line.startsWith('--- ') || line.startsWith('+++ ')) { diff --git a/script/tool/lib/src/fetch_deps_command.dart b/script/tool/lib/src/fetch_deps_command.dart index 45a59f61fa90..0645bd08836d 100644 --- a/script/tool/lib/src/fetch_deps_command.dart +++ b/script/tool/lib/src/fetch_deps_command.dart @@ -32,31 +32,52 @@ class FetchDepsCommand extends PackageLoopingCommand { super.gitDir, }) { argParser.addFlag(_dartFlag, defaultsTo: true, help: 'Run "pub get"'); - argParser.addFlag(_supportingTargetPlatformsOnlyFlag, - help: 'Restricts "pub get" runs to packages that have at least one ' - 'example supporting at least one of the platform flags passed.\n' - 'If no platform flags are passed, this will exclude all packages.'); - argParser.addFlag(platformAndroid, - help: 'Run "gradlew dependencies" for Android plugins.\n' - 'Include packages with Android examples when used with ' - '--$_supportingTargetPlatformsOnlyFlag'); - argParser.addFlag(platformIOS, - help: 'Run "pod install" for iOS plugins.\n' - 'Include packages with iOS examples when used with ' - '--$_supportingTargetPlatformsOnlyFlag'); - argParser.addFlag(platformLinux, - help: 'Include packages with Linux examples when used with ' - '--$_supportingTargetPlatformsOnlyFlag'); - argParser.addFlag(platformMacOS, - help: 'Run "pod install" for macOS plugins.\n' - 'Include packages with macOS examples when used with ' - '--$_supportingTargetPlatformsOnlyFlag'); - argParser.addFlag(platformWeb, - help: 'Include packages with Web examples when used with ' - '--$_supportingTargetPlatformsOnlyFlag'); - argParser.addFlag(platformWindows, - help: 'Include packages with Windows examples when used with ' - '--$_supportingTargetPlatformsOnlyFlag'); + argParser.addFlag( + _supportingTargetPlatformsOnlyFlag, + help: + 'Restricts "pub get" runs to packages that have at least one ' + 'example supporting at least one of the platform flags passed.\n' + 'If no platform flags are passed, this will exclude all packages.', + ); + argParser.addFlag( + platformAndroid, + help: + 'Run "gradlew dependencies" for Android plugins.\n' + 'Include packages with Android examples when used with ' + '--$_supportingTargetPlatformsOnlyFlag', + ); + argParser.addFlag( + platformIOS, + help: + 'Run "pod install" for iOS plugins.\n' + 'Include packages with iOS examples when used with ' + '--$_supportingTargetPlatformsOnlyFlag', + ); + argParser.addFlag( + platformLinux, + help: + 'Include packages with Linux examples when used with ' + '--$_supportingTargetPlatformsOnlyFlag', + ); + argParser.addFlag( + platformMacOS, + help: + 'Run "pod install" for macOS plugins.\n' + 'Include packages with macOS examples when used with ' + '--$_supportingTargetPlatformsOnlyFlag', + ); + argParser.addFlag( + platformWeb, + help: + 'Include packages with Web examples when used with ' + '--$_supportingTargetPlatformsOnlyFlag', + ); + argParser.addFlag( + platformWindows, + help: + 'Include packages with Windows examples when used with ' + '--$_supportingTargetPlatformsOnlyFlag', + ); } static const String _dartFlag = 'dart'; @@ -109,11 +130,12 @@ class FetchDepsCommand extends PackageLoopingCommand { @override Future runForPackage(RepositoryPackage package) async { - bool fetchedDeps = false; - final List skips = []; + var fetchedDeps = false; + final skips = []; if (getBoolArg(_dartFlag)) { - final bool filterPlatforms = - getBoolArg(_supportingTargetPlatformsOnlyFlag); + final bool filterPlatforms = getBoolArg( + _supportingTargetPlatformsOnlyFlag, + ); if (!filterPlatforms || _hasExampleSupportingRequestedPlatform(package)) { fetchedDeps = true; if (!await _fetchDartPackages(package)) { @@ -122,12 +144,14 @@ class FetchDepsCommand extends PackageLoopingCommand { return PackageResult.fail(['Failed to "pub get".']); } } else { - skips.add('Skipping Dart dependencies; no examples support requested ' - 'platforms.'); + skips.add( + 'Skipping Dart dependencies; no examples support requested ' + 'platforms.', + ); } } - final List errors = []; + final errors = []; for (final FlutterPlatform platform in _targetPlatforms) { final PackageResult result; switch (platform) { @@ -170,19 +194,30 @@ class FetchDepsCommand extends PackageLoopingCommand { } Future _fetchAndroidDeps(RepositoryPackage package) async { - if (!pluginSupportsPlatform(platformAndroid, package, - requiredMode: PlatformSupport.inline)) { + if (!pluginSupportsPlatform( + platformAndroid, + package, + requiredMode: PlatformSupport.inline, + )) { return PackageResult.skip( - 'Package does not have native Android dependencies.'); + 'Package does not have native Android dependencies.', + ); } for (final RepositoryPackage example in package.getExamples()) { - final GradleProject gradleProject = GradleProject(example, - processRunner: processRunner, platform: platform); + final gradleProject = GradleProject( + example, + processRunner: processRunner, + platform: platform, + ); if (!gradleProject.isConfigured()) { final bool buildSuccess = await runConfigOnlyBuild( - example, processRunner, platform, FlutterPlatform.android); + example, + processRunner, + platform, + FlutterPlatform.android, + ); if (!buildSuccess) { printError('Unable to configure Gradle project.'); return PackageResult.fail(['Unable to configure Gradle.']); @@ -191,8 +226,9 @@ class FetchDepsCommand extends PackageLoopingCommand { final String packageName = package.directory.basename; - final int exitCode = - await gradleProject.runCommand('$packageName:dependencies'); + final int exitCode = await gradleProject.runCommand( + '$packageName:dependencies', + ); if (exitCode != 0) { return PackageResult.fail(); } @@ -202,24 +238,31 @@ class FetchDepsCommand extends PackageLoopingCommand { } Future _fetchDarwinDeps( - RepositoryPackage package, final String platformString) async { - if (!pluginSupportsPlatform(platformString, package, - requiredMode: PlatformSupport.inline)) { + RepositoryPackage package, + final String platformString, + ) async { + if (!pluginSupportsPlatform( + platformString, + package, + requiredMode: PlatformSupport.inline, + )) { // Convert from the flag (lower case ios/macos) to the actual name. final String displayPlatform = platformString.replaceFirst('os', 'OS'); return PackageResult.skip( - 'Package does not have native $displayPlatform dependencies.'); + 'Package does not have native $displayPlatform dependencies.', + ); } for (final RepositoryPackage example in package.getExamples()) { // Create the necessary native build files, which will run pub get and pod install if needed. final bool buildSuccess = await runConfigOnlyBuild( - example, - processRunner, - platform, - platformString == platformIOS - ? FlutterPlatform.ios - : FlutterPlatform.macos); + example, + processRunner, + platform, + platformString == platformIOS + ? FlutterPlatform.ios + : FlutterPlatform.macos, + ); if (!buildSuccess) { printError('Unable to prepare native project files.'); return PackageResult.fail(['Unable to configure project.']); @@ -230,11 +273,11 @@ class FetchDepsCommand extends PackageLoopingCommand { } Future _fetchDartPackages(RepositoryPackage package) async { - final List packagesToGet = [ + final packagesToGet = [ package, - ...package.getSubpackages(includeExamples: false) + ...package.getSubpackages(includeExamples: false), ]; - for (final RepositoryPackage p in packagesToGet) { + for (final p in packagesToGet) { if (!await runPubGet(p, processRunner, platform)) { return false; } @@ -245,7 +288,8 @@ class FetchDepsCommand extends PackageLoopingCommand { bool _hasExampleSupportingRequestedPlatform(RepositoryPackage package) { return package.getExamples().any((RepositoryPackage example) { return _targetPlatforms.any( - (FlutterPlatform platform) => example.appSupportsPlatform(platform)); + (FlutterPlatform platform) => example.appSupportsPlatform(platform), + ); }); } diff --git a/script/tool/lib/src/firebase_test_lab_command.dart b/script/tool/lib/src/firebase_test_lab_command.dart index 3555ce1705d6..5ab5b9c5d7b8 100644 --- a/script/tool/lib/src/firebase_test_lab_command.dart +++ b/script/tool/lib/src/firebase_test_lab_command.dart @@ -27,34 +27,39 @@ class FirebaseTestLabCommand extends PackageLoopingCommand { super.platform, super.gitDir, }) { + argParser.addOption(_gCloudProjectArg, help: 'The Firebase project name.'); argParser.addOption( - _gCloudProjectArg, - help: 'The Firebase project name.', + _gCloudServiceKeyArg, + help: + 'The path to the service key for gcloud authentication.\n' + 'If not provided, setup will be skipped, so testing will fail ' + 'unless gcloud is already configured.', + ); + argParser.addOption( + 'test-run-id', + defaultsTo: const Uuid().v4(), + help: + 'Optional string to append to the results path, to avoid conflicts. ' + 'Randomly chosen on each invocation if none is provided. ' + 'The default shown here is just an example.', + ); + argParser.addOption( + 'build-id', + defaultsTo: io.Platform.environment['CIRRUS_BUILD_ID'] ?? 'unknown_build', + help: + 'Optional string to append to the results path, to avoid conflicts. ' + r'Defaults to $CIRRUS_BUILD_ID if that is set.', + ); + argParser.addMultiOption( + 'device', + splitCommas: false, + defaultsTo: [ + 'model=walleye,version=26', + 'model=redfin,version=30', + ], + help: + 'Device model(s) to test. See https://cloud.google.com/sdk/gcloud/reference/firebase/test/android/run for more info', ); - argParser.addOption(_gCloudServiceKeyArg, - help: 'The path to the service key for gcloud authentication.\n' - 'If not provided, setup will be skipped, so testing will fail ' - 'unless gcloud is already configured.'); - argParser.addOption('test-run-id', - defaultsTo: const Uuid().v4(), - help: - 'Optional string to append to the results path, to avoid conflicts. ' - 'Randomly chosen on each invocation if none is provided. ' - 'The default shown here is just an example.'); - argParser.addOption('build-id', - defaultsTo: - io.Platform.environment['CIRRUS_BUILD_ID'] ?? 'unknown_build', - help: - 'Optional string to append to the results path, to avoid conflicts. ' - r'Defaults to $CIRRUS_BUILD_ID if that is set.'); - argParser.addMultiOption('device', - splitCommas: false, - defaultsTo: [ - 'model=walleye,version=26', - 'model=redfin,version=30' - ], - help: - 'Device model(s) to test. See https://cloud.google.com/sdk/gcloud/reference/firebase/test/android/run for more info'); argParser.addOption(_gCloudResultsBucketArg, mandatory: true); argParser.addOption( kEnableExperiment, @@ -71,7 +76,8 @@ class FirebaseTestLabCommand extends PackageLoopingCommand { final String name = 'firebase-test-lab'; @override - final String description = 'Runs the instrumentation tests of the example ' + final String description = + 'Runs the instrumentation tests of the example ' 'apps on Firebase Test Lab.\n\n' 'Runs tests in test_instrumentation folder using the ' 'instrumentation_test package.'; @@ -86,15 +92,12 @@ class FirebaseTestLabCommand extends PackageLoopingCommand { final String serviceKey = getStringArg(_gCloudServiceKeyArg); if (serviceKey.isEmpty) { print( - 'No --$_gCloudServiceKeyArg provided; skipping gcloud authorization'); + 'No --$_gCloudServiceKeyArg provided; skipping gcloud authorization', + ); } else { final io.ProcessResult result = await processRunner.run( 'gcloud', - [ - 'auth', - 'activate-service-account', - '--key-file=$serviceKey', - ], + ['auth', 'activate-service-account', '--key-file=$serviceKey'], logOnError: true, ); if (result.exitCode != 0) { @@ -117,7 +120,8 @@ class FirebaseTestLabCommand extends PackageLoopingCommand { print('Firebase project configured.'); } else { logWarning( - 'Warning: gcloud config set returned a non-zero exit code. Continuing anyway.'); + 'Warning: gcloud config set returned a non-zero exit code. Continuing anyway.', + ); } } _firebaseProjectConfigured = true; @@ -130,20 +134,23 @@ class FirebaseTestLabCommand extends PackageLoopingCommand { @override Future runForPackage(RepositoryPackage package) async { - final List results = []; + final results = []; for (final RepositoryPackage example in package.getExamples()) { results.add(await _runForExample(example, package: package)); } // If all results skipped, report skip overall. - if (results - .every((PackageResult result) => result.state == RunState.skipped)) { + if (results.every( + (PackageResult result) => result.state == RunState.skipped, + )) { return PackageResult.skip('No examples support Android.'); } // Otherwise, report failure if there were any failures. final List allErrors = results - .map((PackageResult result) => - result.state == RunState.failed ? result.details : []) + .map( + (PackageResult result) => + result.state == RunState.failed ? result.details : [], + ) .expand((List list) => list) .toList(); return allErrors.isEmpty @@ -156,11 +163,13 @@ class FirebaseTestLabCommand extends PackageLoopingCommand { RepositoryPackage example, { required RepositoryPackage package, }) async { - final Directory androidDirectory = - example.platformDirectory(FlutterPlatform.android); + final Directory androidDirectory = example.platformDirectory( + FlutterPlatform.android, + ); if (!androidDirectory.existsSync()) { return PackageResult.skip( - '${example.displayName} does not support Android.'); + '${example.displayName} does not support Android.', + ); } final Directory uiTestDirectory = androidDirectory @@ -170,25 +179,32 @@ class FirebaseTestLabCommand extends PackageLoopingCommand { if (!uiTestDirectory.existsSync()) { printError('No androidTest directory found.'); if (isFlutterPlugin(package)) { - return PackageResult.fail( - ['No tests ran (use --exclude if this is intentional).']); + return PackageResult.fail([ + 'No tests ran (use --exclude if this is intentional).', + ]); } else { return PackageResult.skip( - '${example.displayName} has no native Android tests.'); + '${example.displayName} has no native Android tests.', + ); } } // Ensure that the Dart integration tests will be run, not just native UI // tests. if (!await _testsContainDartIntegrationTestRunner(uiTestDirectory)) { - printError('No integration_test runner found. ' - 'See the integration_test package README for setup instructions.'); + printError( + 'No integration_test runner found. ' + 'See the integration_test package README for setup instructions.', + ); return PackageResult.fail(['No integration_test runner.']); } // Ensures that gradle wrapper exists - final GradleProject project = GradleProject(example, - processRunner: processRunner, platform: platform); + final project = GradleProject( + example, + processRunner: processRunner, + platform: platform, + ); if (!await _ensureGradleWrapperExists(example, project)) { return PackageResult.fail(['Unable to build example apk']); } @@ -199,14 +215,16 @@ class FirebaseTestLabCommand extends PackageLoopingCommand { return PackageResult.fail(['Unable to assemble androidTest']); } - final List errors = []; + final errors = []; // Used within the loop to ensure a unique GCS output location for each // test file's run. - int resultsCounter = 0; + var resultsCounter = 0; for (final File test in _findIntegrationTestFiles(example)) { - final String testName = - getRelativePosixPath(test, from: package.directory); + final String testName = getRelativePosixPath( + test, + from: package.directory, + ); print('Testing $testName...'); if (!await _runGradle(project, 'app:assembleDebug', testFile: test)) { printError('Could not build $testName'); @@ -215,7 +233,7 @@ class FirebaseTestLabCommand extends PackageLoopingCommand { } final String buildId = getStringArg('build-id'); final String testRunId = getStringArg('test-run-id'); - final String resultsDir = + final resultsDir = 'plugins_android_test/${package.displayName}/$buildId/$testRunId/' '${example.directory.basename}/${resultsCounter++}/'; @@ -224,9 +242,9 @@ class FirebaseTestLabCommand extends PackageLoopingCommand { // entire shard for a flake in any one test is extremely slow. This should // be removed once the root cause of the flake is understood. // See https://github.com/flutter/flutter/issues/95063 - const int maxRetries = 2; - bool passing = false; - for (int i = 1; i <= maxRetries && !passing; ++i) { + const maxRetries = 2; + var passing = false; + for (var i = 1; i <= maxRetries && !passing; ++i) { if (i > 1) { logWarning('$testName failed on attempt ${i - 1}. Retrying...'); } @@ -253,7 +271,9 @@ class FirebaseTestLabCommand extends PackageLoopingCommand { /// /// Returns true if either gradlew was already present, or the build succeeds. Future _ensureGradleWrapperExists( - RepositoryPackage package, GradleProject project) async { + RepositoryPackage package, + GradleProject project, + ) async { // Unconditionally re-run build with --debug --config-only, to ensure that // the project is in a debug state even if it was previously configured. print('Running flutter build apk...'); @@ -280,7 +300,7 @@ class FirebaseTestLabCommand extends PackageLoopingCommand { File test, { required String resultsDir, }) async { - final List args = [ + final args = [ 'firebase', 'test', 'android', @@ -297,11 +317,14 @@ class FirebaseTestLabCommand extends PackageLoopingCommand { '--results-dir=$resultsDir', for (final String device in getStringListArg('device')) ...[ '--device', - device + device, ], ]; - final int exitCode = await processRunner.runAndStream('gcloud', args, - workingDir: example.directory); + final int exitCode = await processRunner.runAndStream( + 'gcloud', + args, + workingDir: example.directory, + ); return exitCode == 0; } @@ -341,8 +364,9 @@ class FirebaseTestLabCommand extends PackageLoopingCommand { /// Finds and returns all integration test files for [example]. Iterable _findIntegrationTestFiles(RepositoryPackage example) sync* { - final Directory integrationTestDir = - example.directory.childDirectory('integration_test'); + final Directory integrationTestDir = example.directory.childDirectory( + 'integration_test', + ); if (!integrationTestDir.existsSync()) { return; @@ -350,8 +374,10 @@ class FirebaseTestLabCommand extends PackageLoopingCommand { yield* integrationTestDir .listSync(recursive: true) - .where((FileSystemEntity file) => - file is File && file.basename.endsWith('_test.dart')) + .where( + (FileSystemEntity file) => + file is File && file.basename.endsWith('_test.dart'), + ) .cast(); } @@ -359,22 +385,23 @@ class FirebaseTestLabCommand extends PackageLoopingCommand { /// annotation that means that the test will reports the results of running /// the Dart integration tests. Future _testsContainDartIntegrationTestRunner( - Directory uiTestDirectory) async { + Directory uiTestDirectory, + ) async { return uiTestDirectory .list(recursive: true, followLinks: false) .where((FileSystemEntity entity) => entity is File) .cast() .any((File file) { - if (file.basename.endsWith('.java')) { - return file - .readAsStringSync() - .contains('@RunWith(FlutterTestRunner.class)'); - } else if (file.basename.endsWith('.kt')) { - return file - .readAsStringSync() - .contains('@RunWith(FlutterTestRunner::class)'); - } - return false; - }); + if (file.basename.endsWith('.java')) { + return file.readAsStringSync().contains( + '@RunWith(FlutterTestRunner.class)', + ); + } else if (file.basename.endsWith('.kt')) { + return file.readAsStringSync().contains( + '@RunWith(FlutterTestRunner::class)', + ); + } + return false; + }); } } diff --git a/script/tool/lib/src/fix_command.dart b/script/tool/lib/src/fix_command.dart index 651af0cf4102..29a7af0a5088 100644 --- a/script/tool/lib/src/fix_command.dart +++ b/script/tool/lib/src/fix_command.dart @@ -20,7 +20,8 @@ class FixCommand extends PackageLoopingCommand { final String name = 'fix'; @override - final String description = 'Fixes packages using dart fix.\n\n' + final String description = + 'Fixes packages using dart fix.\n\n' 'This command requires "dart" and "flutter" to be in your path, and ' 'assumes that dependencies have already been fetched (e.g., by running ' 'the analyze command first).'; @@ -34,9 +35,10 @@ class FixCommand extends PackageLoopingCommand { @override Future runForPackage(RepositoryPackage package) async { - final int exitCode = await processRunner.runAndStream( - 'dart', ['fix', '--apply'], - workingDir: package.directory); + final int exitCode = await processRunner.runAndStream('dart', [ + 'fix', + '--apply', + ], workingDir: package.directory); if (exitCode != 0) { printError('Unable to automatically fix package.'); return PackageResult.fail(); diff --git a/script/tool/lib/src/format_command.dart b/script/tool/lib/src/format_command.dart index 72e55ae0d7b3..87cc37cb411c 100644 --- a/script/tool/lib/src/format_command.dart +++ b/script/tool/lib/src/format_command.dart @@ -39,10 +39,14 @@ const int _exitKotlinFormatFailed = 9; const int _exitSwiftLintFoundIssues = 10; const int _exitDartLanguageVersionIssue = 11; -final Uri _javaFormatterUrl = Uri.https('github.com', - '/google/google-java-format/releases/download/google-java-format-1.3/google-java-format-1.3-all-deps.jar'); -final Uri _kotlinFormatterUrl = Uri.https('maven.org', - '/maven2/com/facebook/ktfmt/0.46/ktfmt-0.46-jar-with-dependencies.jar'); +final Uri _javaFormatterUrl = Uri.https( + 'github.com', + '/google/google-java-format/releases/download/google-java-format-1.3/google-java-format-1.3-all-deps.jar', +); +final Uri _kotlinFormatterUrl = Uri.https( + 'maven.org', + '/maven2/com/facebook/ktfmt/0.46/ktfmt-0.46-jar-with-dependencies.jar', +); /// A command to format all package code. class FormatCommand extends PackageLoopingCommand { @@ -55,22 +59,37 @@ class FormatCommand extends PackageLoopingCommand { }) { argParser.addFlag(_failonChangeArg, hide: true); argParser.addFlag(_dartArg, help: 'Format Dart files', defaultsTo: true); - argParser.addFlag(_clangFormatArg, - help: 'Format with "clang-format"', defaultsTo: true); - argParser.addFlag(_kotlinArg, - help: 'Format Kotlin files', defaultsTo: true); + argParser.addFlag( + _clangFormatArg, + help: 'Format with "clang-format"', + defaultsTo: true, + ); + argParser.addFlag( + _kotlinArg, + help: 'Format Kotlin files', + defaultsTo: true, + ); argParser.addFlag(_javaArg, help: 'Format Java files', defaultsTo: true); // Currently swift-format is run via xcrun, so only works on macOS. If that // ever becomes an issue, the ability to find it in the path and/or allow // providing a path could be restored, to allow developers on Linux or // Windows to build swift-format from source and use that. See // https://github.com/flutter/packages/pull/9460. - argParser.addFlag(_swiftArg, - help: 'Format and lint Swift files', defaultsTo: platform.isMacOS); - argParser.addOption(_clangFormatPathArg, - defaultsTo: 'clang-format', help: 'Path to "clang-format" executable.'); - argParser.addOption(_javaPathArg, - defaultsTo: 'java', help: 'Path to "java" executable.'); + argParser.addFlag( + _swiftArg, + help: 'Format and lint Swift files', + defaultsTo: platform.isMacOS, + ); + argParser.addOption( + _clangFormatPathArg, + defaultsTo: 'clang-format', + help: 'Path to "clang-format" executable.', + ); + argParser.addOption( + _javaPathArg, + defaultsTo: 'java', + help: 'Path to "java" executable.', + ); } static const String _dartArg = 'dart'; @@ -104,8 +123,10 @@ class FormatCommand extends PackageLoopingCommand { // Dart has to be run per-package because the formatter can have different // behavior based on the package's SDK, which can't be determined if the // formatter isn't running in the context of the package. - final Iterable files = - await _getFilteredFilePaths(getFiles(), relativeTo: packagesDir); + final Iterable files = await _getFilteredFilePaths( + getFiles(), + relativeTo: packagesDir, + ); if (getBoolArg(_javaArg)) { await _formatJava(files, javaFormatterPath); } @@ -157,7 +178,7 @@ class FormatCommand extends PackageLoopingCommand { 'ls-files', '--modified', packagesDir.path, - thirdPartyPackagesDir.path + thirdPartyPackagesDir.path, ], workingDir: packagesDir.parent, logOnError: true, @@ -169,7 +190,7 @@ class FormatCommand extends PackageLoopingCommand { print('\n\n'); - final String stdout = modifiedFiles.stdout as String; + final stdout = modifiedFiles.stdout as String; if (stdout.isEmpty) { print('All files formatted correctly.'); return false; @@ -178,9 +199,11 @@ class FormatCommand extends PackageLoopingCommand { print('These files are not formatted correctly (see diff below):'); LineSplitter.split(stdout).map((String line) => ' $line').forEach(print); - print('\nTo fix run the repository tooling `format` command: ' - 'https://github.com/flutter/packages/blob/main/script/tool/README.md#format-code\n' - 'or copy-paste this command into your terminal:'); + print( + '\nTo fix run the repository tooling `format` command: ' + 'https://github.com/flutter/packages/blob/main/script/tool/README.md#format-code\n' + 'or copy-paste this command into your terminal:', + ); final io.ProcessResult diff = await processRunner.run( 'git', @@ -199,46 +222,52 @@ class FormatCommand extends PackageLoopingCommand { } Future _formatCppAndObjectiveC(Iterable files) async { - final Iterable clangFiles = _getPathsWithExtensions( - files, {'.h', '.m', '.mm', '.cc', '.cpp'}); + final Iterable clangFiles = _getPathsWithExtensions(files, { + '.h', + '.m', + '.mm', + '.cc', + '.cpp', + }); if (clangFiles.isNotEmpty) { final String clangFormat = await _findValidClangFormat(); print('Formatting .cc, .cpp, .h, .m, and .mm files...'); - final int exitCode = await _runBatched( - clangFormat, ['-i', '--style=file'], - files: clangFiles); + final int exitCode = await _runBatched(clangFormat, [ + '-i', + '--style=file', + ], files: clangFiles); if (exitCode != 0) { printError( - 'Failed to format C, C++, and Objective-C files: exit code $exitCode.'); + 'Failed to format C, C++, and Objective-C files: exit code $exitCode.', + ); throw ToolExit(_exitClangFormatFailed); } } } Future _formatAndLintSwift(Iterable files) async { - final Iterable swiftFiles = - _getPathsWithExtensions(files, {'.swift'}); + final Iterable swiftFiles = _getPathsWithExtensions(files, { + '.swift', + }); if (swiftFiles.isNotEmpty) { print('Formatting .swift files...'); - final int formatExitCode = await _runBatched( - 'xcrun', ['swift-format', '-i'], - files: swiftFiles); + final int formatExitCode = await _runBatched('xcrun', [ + 'swift-format', + '-i', + ], files: swiftFiles); if (formatExitCode != 0) { printError('Failed to format Swift files: exit code $formatExitCode.'); throw ToolExit(_exitSwiftFormatFailed); } print('Linting .swift files...'); - final int lintExitCode = await _runBatched( - 'xcrun', - [ - 'swift-format', - 'lint', - '--parallel', - '--strict', - ], - files: swiftFiles); + final int lintExitCode = await _runBatched('xcrun', [ + 'swift-format', + 'lint', + '--parallel', + '--strict', + ], files: swiftFiles); if (lintExitCode == 1) { printError('Swift linter found issues. See above for linter output.'); throw ToolExit(_exitSwiftLintFoundIssues); @@ -264,27 +293,33 @@ class FormatCommand extends PackageLoopingCommand { return clangFormatPath; } } - printError('Unable to run "clang-format". Make sure that it is in your ' - 'path, or provide a full path with --$_clangFormatPathArg.'); + printError( + 'Unable to run "clang-format". Make sure that it is in your ' + 'path, or provide a full path with --$_clangFormatPathArg.', + ); throw ToolExit(_exitDependencyMissing); } Future _formatJava(Iterable files, String formatterPath) async { - final Iterable javaFiles = - _getPathsWithExtensions(files, {'.java'}); + final Iterable javaFiles = _getPathsWithExtensions(files, { + '.java', + }); if (javaFiles.isNotEmpty) { final String java = getStringArg(_javaPathArg); if (!await _hasDependency(java)) { printError( - 'Unable to run "java". Make sure that it is in your path, or ' - 'provide a full path with --$_javaPathArg.'); + 'Unable to run "java". Make sure that it is in your path, or ' + 'provide a full path with --$_javaPathArg.', + ); throw ToolExit(_exitDependencyMissing); } print('Formatting .java files...'); - final int exitCode = await _runBatched( - java, ['-jar', formatterPath, '--replace'], - files: javaFiles); + final int exitCode = await _runBatched(java, [ + '-jar', + formatterPath, + '--replace', + ], files: javaFiles); if (exitCode != 0) { printError('Failed to format Java files: exit code $exitCode.'); throw ToolExit(_exitJavaFormatFailed); @@ -293,22 +328,28 @@ class FormatCommand extends PackageLoopingCommand { } Future _formatKotlin( - Iterable files, String formatterPath) async { - final Iterable kotlinFiles = - _getPathsWithExtensions(files, {'.kt'}); + Iterable files, + String formatterPath, + ) async { + final Iterable kotlinFiles = _getPathsWithExtensions( + files, + {'.kt'}, + ); if (kotlinFiles.isNotEmpty) { final String java = getStringArg(_javaPathArg); if (!await _hasDependency(java)) { printError( - 'Unable to run "java". Make sure that it is in your path, or ' - 'provide a full path with --$_javaPathArg.'); + 'Unable to run "java". Make sure that it is in your path, or ' + 'provide a full path with --$_javaPathArg.', + ); throw ToolExit(_exitDependencyMissing); } print('Formatting .kt files...'); - final int exitCode = await _runBatched( - java, ['-jar', formatterPath], - files: kotlinFiles); + final int exitCode = await _runBatched(java, [ + '-jar', + formatterPath, + ], files: kotlinFiles); if (exitCode != 0) { printError('Failed to format Kotlin files: exit code $exitCode.'); throw ToolExit(_exitKotlinFormatFailed); @@ -325,18 +366,19 @@ class FormatCommand extends PackageLoopingCommand { Iterable files, { Directory? workingDir, }) async { - final Iterable dartFiles = - _getPathsWithExtensions(files, {'.dart'}); + final Iterable dartFiles = _getPathsWithExtensions(files, { + '.dart', + }); if (dartFiles.isNotEmpty) { - final List packagesToGet = [ + final packagesToGet = [ package, - ...package.getSubpackages(includeExamples: false) + ...package.getSubpackages(includeExamples: false), ]; // Ensure that the package language version has been correctly resolved, // since it can change the behavior of the Dart formatter. This must be // done for every sub-package to avoid inconsistent results if // sub-packages have different language versions than the main package. - for (final RepositoryPackage p in packagesToGet) { + for (final p in packagesToGet) { if (!_resolvedLanguageVersionIsUpToDate(p)) { if (!await runPubGet(p, processRunner, platform)) { printError('Unable to fetch dependencies.'); @@ -346,8 +388,12 @@ class FormatCommand extends PackageLoopingCommand { } print('Formatting .dart files...'); - final int exitCode = await _runBatched('dart', ['format'], - files: dartFiles, workingDir: workingDir); + final int exitCode = await _runBatched( + 'dart', + ['format'], + files: dartFiles, + workingDir: workingDir, + ); if (exitCode != 0) { printError('Failed to format Dart files: exit code $exitCode.'); throw ToolExit(_exitFlutterFormatFailed); @@ -386,8 +432,8 @@ class FormatCommand extends PackageLoopingCommand { // In the event that code ownership moves to someone who does not hold the // same views as the original owner, the pragma can be removed and the file // auto-formatted. - const String handFormattedExtension = '.dart'; - const String handFormattedPragma = '// This file is hand-formatted.'; + const handFormattedExtension = '.dart'; + const handFormattedPragma = '// This file is hand-formatted.'; return files .where((File file) { @@ -396,32 +442,42 @@ class FormatCommand extends PackageLoopingCommand { !file.readAsLinesSync().contains(handFormattedPragma); }) .map((File file) => path.relative(file.path, from: fromPath)) - .where((String path) => - // Ignore files in build/ directories (e.g., headers of frameworks) - // to avoid useless extra work in local repositories. - !path.contains( - pathFragmentForDirectories(['example', 'build'])) && - // Ignore files in Pods, which are not part of the repository. - !path.contains(pathFragmentForDirectories(['Pods'])) && - // See https://github.com/flutter/flutter/issues/144039 - !path.endsWith('GeneratedPluginRegistrant.swift') && - // Ignore .dart_tool/, which can have various intermediate files. - !path.contains(pathFragmentForDirectories(['.dart_tool']))) + .where( + (String path) => + // Ignore files in build/ directories (e.g., headers of frameworks) + // to avoid useless extra work in local repositories. + !path.contains( + pathFragmentForDirectories(['example', 'build']), + ) && + // Ignore files in Pods, which are not part of the repository. + !path.contains(pathFragmentForDirectories(['Pods'])) && + // See https://github.com/flutter/flutter/issues/144039 + !path.endsWith('GeneratedPluginRegistrant.swift') && + // Ignore .dart_tool/, which can have various intermediate files. + !path.contains( + pathFragmentForDirectories(['.dart_tool']), + ), + ) .toList(); } Iterable _getPathsWithExtensions( - Iterable files, Set extensions) { + Iterable files, + Set extensions, + ) { return files.where( - (String filePath) => extensions.contains(path.extension(filePath))); + (String filePath) => extensions.contains(path.extension(filePath)), + ); } Future _getJavaFormatterPath() async { final String javaFormatterPath = path.join( - path.dirname(path.fromUri(platform.script)), - 'google-java-format-1.3-all-deps.jar'); - final File javaFormatterFile = - packagesDir.fileSystem.file(javaFormatterPath); + path.dirname(path.fromUri(platform.script)), + 'google-java-format-1.3-all-deps.jar', + ); + final File javaFormatterFile = packagesDir.fileSystem.file( + javaFormatterPath, + ); if (!javaFormatterFile.existsSync()) { print('Downloading Google Java Format...'); @@ -434,10 +490,12 @@ class FormatCommand extends PackageLoopingCommand { Future _getKotlinFormatterPath() async { final String kotlinFormatterPath = path.join( - path.dirname(path.fromUri(platform.script)), - 'ktfmt-0.46-jar-with-dependencies.jar'); - final File kotlinFormatterFile = - packagesDir.fileSystem.file(kotlinFormatterPath); + path.dirname(path.fromUri(platform.script)), + 'ktfmt-0.46-jar-with-dependencies.jar', + ); + final File kotlinFormatterFile = packagesDir.fileSystem.file( + kotlinFormatterPath, + ); if (!kotlinFormatterFile.existsSync()) { print('Downloading ktfmt...'); @@ -452,10 +510,11 @@ class FormatCommand extends PackageLoopingCommand { Future _hasDependency(String command) async { // Some versions of Java accept both -version and --version, but some only // accept -version. - final String versionFlag = command == 'java' ? '-version' : '--version'; + final versionFlag = command == 'java' ? '-version' : '--version'; try { - final io.ProcessResult result = - await processRunner.run(command, [versionFlag]); + final io.ProcessResult result = await processRunner.run(command, [ + versionFlag, + ]); if (result.exitCode != 0) { return false; } @@ -469,8 +528,10 @@ class FormatCommand extends PackageLoopingCommand { /// Returns all instances of [command] executable found on user path. Future> _whichAll(String command) async { try { - final io.ProcessResult result = - await processRunner.run('which', ['-a', command]); + final io.ProcessResult result = await processRunner.run('which', [ + '-a', + command, + ]); if (result.exitCode != 0) { return []; @@ -491,26 +552,36 @@ class FormatCommand extends PackageLoopingCommand { /// /// Returns the exit code of the first failure, which stops the run, or 0 /// on success. - Future _runBatched(String command, List arguments, - {required Iterable files, Directory? workingDir}) async { - final int commandLineMax = - platform.isWindows ? windowsCommandLineMax : nonWindowsCommandLineMax; + Future _runBatched( + String command, + List arguments, { + required Iterable files, + Directory? workingDir, + }) async { + final int commandLineMax = platform.isWindows + ? windowsCommandLineMax + : nonWindowsCommandLineMax; // Compute the max length of the file argument portion of a batch. // Add one to each argument's length for the space before it. - final int argumentTotalLength = - arguments.fold(0, (int sum, String arg) => sum + arg.length + 1); + final int argumentTotalLength = arguments.fold( + 0, + (int sum, String arg) => sum + arg.length + 1, + ); final int batchMaxTotalLength = commandLineMax - command.length - argumentTotalLength; // Run the command in batches. - final List> batches = - _partitionFileList(files, maxStringLength: batchMaxTotalLength); - for (final List batch in batches) { + final List> batches = _partitionFileList( + files, + maxStringLength: batchMaxTotalLength, + ); + for (final batch in batches) { batch.sort(); // For ease of testing. - final int exitCode = await processRunner.runAndStream( - command, [...arguments, ...batch], - workingDir: workingDir ?? packagesDir); + final int exitCode = await processRunner.runAndStream(command, [ + ...arguments, + ...batch, + ], workingDir: workingDir ?? packagesDir); if (exitCode != 0) { return exitCode; } @@ -521,11 +592,13 @@ class FormatCommand extends PackageLoopingCommand { /// Partitions [files] into batches whose max string length as parameters to /// a command (including the spaces between them, and between the list and /// the command itself) is no longer than [maxStringLength]. - List> _partitionFileList(Iterable files, - {required int maxStringLength}) { - final List> batches = >[[]]; - int currentBatchTotalLength = 0; - for (final String file in files) { + List> _partitionFileList( + Iterable files, { + required int maxStringLength, + }) { + final batches = >[[]]; + var currentBatchTotalLength = 0; + for (final file in files) { final int length = file.length + 1 /* for the space */; if (currentBatchTotalLength + length > maxStringLength) { // Start a new batch. @@ -552,7 +625,8 @@ class FormatCommand extends PackageLoopingCommand { final VersionConstraint? dartSdkConstraint = pubspec.environment['sdk']; if (dartSdkConstraint == null) { printError( - '${package.pubspecFile.absolute.path} is missing a Dart SDK constraint'); + '${package.pubspecFile.absolute.path} is missing a Dart SDK constraint', + ); throw ToolExit(_exitDartLanguageVersionIssue); } final String minDartSdkVersion = switch (dartSdkConstraint) { @@ -562,26 +636,30 @@ class FormatCommand extends PackageLoopingCommand { }; final String packageName = pubspec.name; - final Map configJson = + final configJson = jsonDecode(configFile.readAsStringSync()) as Map; final Map? packageInfo = (configJson['packages'] as List?) ?.cast>() .where((Map p) => p['name'] == packageName) .firstOrNull; - final String? resolvedLanguageVersion = - packageInfo == null ? null : packageInfo['languageVersion'] as String?; + final String? resolvedLanguageVersion = packageInfo == null + ? null + : packageInfo['languageVersion'] as String?; if (resolvedLanguageVersion == null) { // This shouldn't ever happen, so log for potential investigation. printWarning( - 'No language version found for $packageName in ${configFile.absolute.path}'); + 'No language version found for $packageName in ${configFile.absolute.path}', + ); return false; } // Check for startsWith rather than equality since the JSON languageVerison // currently only uses major.minor, rather than the full three-part version. if (!minDartSdkVersion.startsWith(resolvedLanguageVersion)) { - print('Resolved language version for $packageName is stale ' - '($resolvedLanguageVersion vs $minDartSdkVersion)'); + print( + 'Resolved language version for $packageName is stale ' + '($resolvedLanguageVersion vs $minDartSdkVersion)', + ); return false; } return true; diff --git a/script/tool/lib/src/gradle_check_command.dart b/script/tool/lib/src/gradle_check_command.dart index 1c45a597ba08..9ad76a2bd8bc 100644 --- a/script/tool/lib/src/gradle_check_command.dart +++ b/script/tool/lib/src/gradle_check_command.dart @@ -22,10 +22,7 @@ final Version minKotlinVersion = Version(1, 7, 10); /// A command to enforce gradle file conventions and best practices. class GradleCheckCommand extends PackageLoopingCommand { /// Creates an instance of the gradle check command. - GradleCheckCommand( - super.packagesDir, { - super.gitDir, - }); + GradleCheckCommand(super.packagesDir, {super.gitDir}); static const int _minimumJavaVersion = 17; @@ -52,8 +49,9 @@ class GradleCheckCommand extends PackageLoopingCommand { return PackageResult.skip('No android/ directory.'); } - const String exampleDirName = 'example'; - final bool isExample = package.directory.basename == exampleDirName || + const exampleDirName = 'example'; + final bool isExample = + package.directory.basename == exampleDirName || package.directory.parent.basename == exampleDirName; if (!_validateBuildGradles(package, isExample: isExample)) { return PackageResult.fail(); @@ -61,28 +59,35 @@ class GradleCheckCommand extends PackageLoopingCommand { return PackageResult.success(); } - bool _validateBuildGradles(RepositoryPackage package, - {required bool isExample}) { - final Directory androidDir = - package.platformDirectory(FlutterPlatform.android); + bool _validateBuildGradles( + RepositoryPackage package, { + required bool isExample, + }) { + final Directory androidDir = package.platformDirectory( + FlutterPlatform.android, + ); final File topLevelGradleFile = _getBuildGradleFile(androidDir); // This is tracked as a variable rather than a sequence of &&s so that all // failures are reported at once, not just the first one. - bool succeeded = true; + var succeeded = true; if (isExample) { if (!_validateExampleTopLevelBuildGradle(package, topLevelGradleFile)) { succeeded = false; } - final File topLevelSettingsGradleFile = - _getSettingsGradleFile(androidDir); + final File topLevelSettingsGradleFile = _getSettingsGradleFile( + androidDir, + ); if (!_validateExampleTopLevelSettingsGradle( - package, topLevelSettingsGradleFile)) { + package, + topLevelSettingsGradleFile, + )) { succeeded = false; } - final File appGradleFile = - _getBuildGradleFile(androidDir.childDirectory('app')); + final File appGradleFile = _getBuildGradleFile( + androidDir.childDirectory('app'), + ); if (!_validateExampleAppBuildGradle(package, appGradleFile)) { succeeded = false; } @@ -101,12 +106,16 @@ class GradleCheckCommand extends PackageLoopingCommand { dir.childFile('settings.gradle'); // Returns the main/AndroidManifest.xml file for the given package. - File _getMainAndroidManifest(RepositoryPackage package, - {required bool isExample}) { - final Directory androidDir = - package.platformDirectory(FlutterPlatform.android); - final Directory baseDir = - isExample ? androidDir.childDirectory('app') : androidDir; + File _getMainAndroidManifest( + RepositoryPackage package, { + required bool isExample, + }) { + final Directory androidDir = package.platformDirectory( + FlutterPlatform.android, + ); + final Directory baseDir = isExample + ? androidDir.childDirectory('app') + : androidDir; return baseDir .childDirectory('src') .childDirectory('main') @@ -118,14 +127,16 @@ class GradleCheckCommand extends PackageLoopingCommand { /// Validates the build.gradle file for a plugin /// (some_plugin/android/build.gradle). bool _validatePluginBuildGradle(RepositoryPackage package, File gradleFile) { - print('${indentation}Validating ' - '${getRelativePosixPath(gradleFile, from: package.directory)}.'); + print( + '${indentation}Validating ' + '${getRelativePosixPath(gradleFile, from: package.directory)}.', + ); final String contents = gradleFile.readAsStringSync(); final List lines = contents.split('\n'); // This is tracked as a variable rather than a sequence of &&s so that all // failures are reported at once, not just the first one. - bool succeeded = true; + var succeeded = true; if (!_validateNamespace(package, contents, isExample: false)) { succeeded = false; } @@ -155,7 +166,8 @@ class GradleCheckCommand extends PackageLoopingCommand { /// String printed as example of valid example root build.gradle repository /// configuration that enables artifact hub env variable. @visibleForTesting - static const String exampleRootGradleArtifactHubString = ''' + static const String exampleRootGradleArtifactHubString = + ''' // See $artifactHubDocumentationString for more info. def artifactRepoKey = 'ARTIFACT_HUB_REPOSITORY' if (System.getenv().containsKey(artifactRepoKey)) { @@ -169,30 +181,45 @@ class GradleCheckCommand extends PackageLoopingCommand { /// /// Required in root gradle file. bool _validateArtifactHubUsage( - RepositoryPackage example, List gradleLines) { + RepositoryPackage example, + List gradleLines, + ) { // Gradle variable name used to hold environment variable string. - const String keyVariable = 'artifactRepoKey'; - final RegExp keyPresentRegex = - RegExp('$keyVariable' r"\s+=\s+'ARTIFACT_HUB_REPOSITORY'"); - final RegExp documentationPresentRegex = RegExp( - r'github\.com.*flutter.*blob.*Plugins-and-Packages-repository-structure.*gradle-structure'); - final RegExp keyReadRegex = - RegExp(r'if.*System\.getenv.*\.containsKey.*' '$keyVariable'); - final RegExp keyUsedRegex = - RegExp(r'maven.*url.*System\.getenv\(' '$keyVariable'); - - final bool keyPresent = - gradleLines.any((String line) => keyPresentRegex.hasMatch(line)); - final bool documentationPresent = gradleLines - .any((String line) => documentationPresentRegex.hasMatch(line)); - final bool keyRead = - gradleLines.any((String line) => keyReadRegex.hasMatch(line)); - final bool keyUsed = - gradleLines.any((String line) => keyUsedRegex.hasMatch(line)); + const keyVariable = 'artifactRepoKey'; + final keyPresentRegex = RegExp( + '$keyVariable' + r"\s+=\s+'ARTIFACT_HUB_REPOSITORY'", + ); + final documentationPresentRegex = RegExp( + r'github\.com.*flutter.*blob.*Plugins-and-Packages-repository-structure.*gradle-structure', + ); + final keyReadRegex = RegExp( + r'if.*System\.getenv.*\.containsKey.*' + '$keyVariable', + ); + final keyUsedRegex = RegExp( + r'maven.*url.*System\.getenv\(' + '$keyVariable', + ); + + final bool keyPresent = gradleLines.any( + (String line) => keyPresentRegex.hasMatch(line), + ); + final bool documentationPresent = gradleLines.any( + (String line) => documentationPresentRegex.hasMatch(line), + ); + final bool keyRead = gradleLines.any( + (String line) => keyReadRegex.hasMatch(line), + ); + final bool keyUsed = gradleLines.any( + (String line) => keyUsedRegex.hasMatch(line), + ); if (!(documentationPresent && keyPresent && keyRead && keyUsed)) { - printError('Failed Artifact Hub validation. Include the following in ' - 'example root build.gradle:\n$exampleRootGradleArtifactHubString'); + printError( + 'Failed Artifact Hub validation. Include the following in ' + 'example root build.gradle:\n$exampleRootGradleArtifactHubString', + ); } return keyPresent && documentationPresent && keyRead && keyUsed; @@ -201,14 +228,18 @@ class GradleCheckCommand extends PackageLoopingCommand { /// Validates the top-level settings.gradle for an example app (e.g., /// some_package/example/android/settings.gradle). bool _validateExampleTopLevelSettingsGradle( - RepositoryPackage package, File gradleSettingsFile) { - print('${indentation}Validating ' - '${getRelativePosixPath(gradleSettingsFile, from: package.directory)}.'); + RepositoryPackage package, + File gradleSettingsFile, + ) { + print( + '${indentation}Validating ' + '${getRelativePosixPath(gradleSettingsFile, from: package.directory)}.', + ); final String contents = gradleSettingsFile.readAsStringSync(); final List lines = contents.split('\n'); // This is tracked as a variable rather than a sequence of &&s so that all // failures are reported at once, not just the first one. - bool succeeded = true; + var succeeded = true; if (!_validateArtifactHubSettingsUsage(package, lines)) { succeeded = false; } @@ -231,16 +262,22 @@ plugins { /// /// Required in root gradle file. bool _validateArtifactHubSettingsUsage( - RepositoryPackage example, List gradleLines) { - final RegExp documentationPresentRegex = RegExp( - r'github\.com.*flutter.*blob.*Plugins-and-Packages-repository-structure.*gradle-structure'); - final RegExp artifactRegistryPluginApplyRegex = RegExp( - r'id.*com\.google\.cloud\.artifactregistry\.gradle-plugin.*version.*\b\d+\.\d+\.\d+\b'); - - final bool documentationPresent = gradleLines - .any((String line) => documentationPresentRegex.hasMatch(line)); - final bool declarativeArtifactRegistryApplied = gradleLines - .any((String line) => artifactRegistryPluginApplyRegex.hasMatch(line)); + RepositoryPackage example, + List gradleLines, + ) { + final documentationPresentRegex = RegExp( + r'github\.com.*flutter.*blob.*Plugins-and-Packages-repository-structure.*gradle-structure', + ); + final artifactRegistryPluginApplyRegex = RegExp( + r'id.*com\.google\.cloud\.artifactregistry\.gradle-plugin.*version.*\b\d+\.\d+\.\d+\b', + ); + + final bool documentationPresent = gradleLines.any( + (String line) => documentationPresentRegex.hasMatch(line), + ); + final bool declarativeArtifactRegistryApplied = gradleLines.any( + (String line) => artifactRegistryPluginApplyRegex.hasMatch(line), + ); final bool validArtifactConfiguration = documentationPresent && declarativeArtifactRegistryApplied; @@ -248,12 +285,15 @@ plugins { printError('Failed Artifact Hub validation.'); if (!documentationPresent) { printError( - 'The link to the Artifact Hub documentation is missing. Include the following in ' - 'example root settings.gradle:\n// See $artifactHubDocumentationString for more info.'); + 'The link to the Artifact Hub documentation is missing. Include the following in ' + 'example root settings.gradle:\n// See $artifactHubDocumentationString for more info.', + ); } if (!declarativeArtifactRegistryApplied) { - printError('Include the following in ' - 'example root settings.gradle:\n$exampleSettingsArtifactHubString'); + printError( + 'Include the following in ' + 'example root settings.gradle:\n$exampleSettingsArtifactHubString', + ); } } return validArtifactConfiguration; @@ -262,15 +302,19 @@ plugins { /// Validates the top-level build.gradle for an example app (e.g., /// some_package/example/android/build.gradle). bool _validateExampleTopLevelBuildGradle( - RepositoryPackage package, File gradleFile) { - print('${indentation}Validating ' - '${getRelativePosixPath(gradleFile, from: package.directory)}.'); + RepositoryPackage package, + File gradleFile, + ) { + print( + '${indentation}Validating ' + '${getRelativePosixPath(gradleFile, from: package.directory)}.', + ); final String contents = gradleFile.readAsStringSync(); final List lines = contents.split('\n'); // This is tracked as a variable rather than a sequence of &&s so that all // failures are reported at once, not just the first one. - bool succeeded = true; + var succeeded = true; if (!_validateJavacLintConfig(package, lines)) { succeeded = false; } @@ -286,14 +330,18 @@ plugins { /// Validates the app-level build.gradle for an example app (e.g., /// some_package/example/android/app/build.gradle). bool _validateExampleAppBuildGradle( - RepositoryPackage package, File gradleFile) { - print('${indentation}Validating ' - '${getRelativePosixPath(gradleFile, from: package.directory)}.'); + RepositoryPackage package, + File gradleFile, + ) { + print( + '${indentation}Validating ' + '${getRelativePosixPath(gradleFile, from: package.directory)}.', + ); final String contents = gradleFile.readAsStringSync(); // This is tracked as a variable rather than a sequence of &&s so that all // failures are reported at once, not just the first one. - bool succeeded = true; + var succeeded = true; if (!_validateNamespace(package, contents, isExample: true)) { succeeded = false; } @@ -302,18 +350,24 @@ plugins { /// Validates that [gradleContents] sets a namespace, which is required for /// compatibility with apps that use AGP 8+. - bool _validateNamespace(RepositoryPackage package, String gradleContents, - {required bool isExample}) { + bool _validateNamespace( + RepositoryPackage package, + String gradleContents, { + required bool isExample, + }) { // Regex to validate that the following namespace definition // is found (where the single quotes can be single or double): // - namespace = 'dev.flutter.foo' - final RegExp nameSpaceRegex = - RegExp('^\\s*namespace\\s+=\\s*[\'"](.*?)[\'"]', multiLine: true); - final RegExpMatch? nameSpaceRegexMatch = - nameSpaceRegex.firstMatch(gradleContents); + final nameSpaceRegex = RegExp( + '^\\s*namespace\\s+=\\s*[\'"](.*?)[\'"]', + multiLine: true, + ); + final RegExpMatch? nameSpaceRegexMatch = nameSpaceRegex.firstMatch( + gradleContents, + ); if (nameSpaceRegexMatch == null) { - const String errorMessage = ''' + const errorMessage = ''' build.gradle must set a "namespace": android { @@ -326,11 +380,15 @@ https://developer.android.com/build/publish-library/prep-lib-release#choose-name '''; printError( - '$indentation${errorMessage.split('\n').join('\n$indentation')}'); + '$indentation${errorMessage.split('\n').join('\n$indentation')}', + ); return false; } else { - return _validateNamespaceMatchesManifest(package, - isExample: isExample, namespace: nameSpaceRegexMatch.group(1)!); + return _validateNamespaceMatchesManifest( + package, + isExample: isExample, + namespace: nameSpaceRegexMatch.group(1)!, + ); } } @@ -339,22 +397,29 @@ https://developer.android.com/build/publish-library/prep-lib-release#choose-name /// where compatibility with AGP <7 is no longer required). /// /// Prints an error and returns false if validation fails. - bool _validateNamespaceMatchesManifest(RepositoryPackage package, - {required bool isExample, required String namespace}) { - final RegExp manifestPackageRegex = RegExp(r'package\s*=\s*"(.*?)"'); - final String manifestContents = - _getMainAndroidManifest(package, isExample: isExample) - .readAsStringSync(); - final RegExpMatch? packageMatch = - manifestPackageRegex.firstMatch(manifestContents); + bool _validateNamespaceMatchesManifest( + RepositoryPackage package, { + required bool isExample, + required String namespace, + }) { + final manifestPackageRegex = RegExp(r'package\s*=\s*"(.*?)"'); + final String manifestContents = _getMainAndroidManifest( + package, + isExample: isExample, + ).readAsStringSync(); + final RegExpMatch? packageMatch = manifestPackageRegex.firstMatch( + manifestContents, + ); if (packageMatch != null && namespace != packageMatch.group(1)) { - final String errorMessage = ''' + final errorMessage = + ''' build.gradle "namespace" must match the "package" attribute in AndroidManifest.xml, if one is present. build.gradle namespace: "$namespace" AndroidMastifest.xml package: "${packageMatch.group(1)}" '''; printError( - '$indentation${errorMessage.split('\n').join('\n$indentation')}'); + '$indentation${errorMessage.split('\n').join('\n$indentation')}', + ); return false; } return true; @@ -364,21 +429,28 @@ build.gradle "namespace" must match the "package" attribute in AndroidManifest.x /// than using whatever the client's local toolchaing defaults to (which can /// lead to compile errors that show up for clients, but not in CI). bool _validateCompatibilityVersions(List gradleLines) { - final bool hasLanguageVersion = gradleLines.any((String line) => - line.contains('languageVersion') && !_isCommented(line)); - final bool hasCompabilityVersions = gradleLines.any((String line) => - line.contains('sourceCompatibility = JavaVersion.VERSION_') && - !_isCommented(line)) && + final bool hasLanguageVersion = gradleLines.any( + (String line) => line.contains('languageVersion') && !_isCommented(line), + ); + final bool hasCompabilityVersions = + gradleLines.any( + (String line) => + line.contains('sourceCompatibility = JavaVersion.VERSION_') && + !_isCommented(line), + ) && // Newer toolchains default targetCompatibility to the same value as // sourceCompatibility, but older toolchains require it to be set // explicitly. The exact version cutoff (and of which piece of the // toolchain; likely AGP) is unknown; for context see // https://github.com/flutter/flutter/issues/125482 - gradleLines.any((String line) => - line.contains('targetCompatibility = JavaVersion.VERSION_') && - !_isCommented(line)); + gradleLines.any( + (String line) => + line.contains('targetCompatibility = JavaVersion.VERSION_') && + !_isCommented(line), + ); if (!hasLanguageVersion && !hasCompabilityVersions) { - const String javaErrorMessage = ''' + const javaErrorMessage = + ''' build.gradle(.kts) must set an explicit Java compatibility version. This can be done either via "sourceCompatibility"/"targetCompatibility": @@ -401,7 +473,8 @@ https://docs.gradle.org/current/userguide/java_plugin.html#toolchain_and_compati for more details.'''; printError( - '$indentation${javaErrorMessage.split('\n').join('\n$indentation')}'); + '$indentation${javaErrorMessage.split('\n').join('\n$indentation')}', + ); return false; } @@ -412,21 +485,27 @@ for more details.'''; bool isKotlinOptions(String line) => line.contains('kotlinOptions') && !_isCommented(line); final bool hasKotlinOptions = gradleLines.any(isKotlinOptions); - final bool kotlinOptionsUsesJavaVersion = gradleLines.any((String line) => - line.contains('jvmTarget = JavaVersion.VERSION_') && - !_isCommented(line)); + final bool kotlinOptionsUsesJavaVersion = gradleLines.any( + (String line) => + line.contains('jvmTarget = JavaVersion.VERSION_') && + !_isCommented(line), + ); // Either does not set kotlinOptions or does and uses non-string based syntax. if (hasKotlinOptions && !kotlinOptionsUsesJavaVersion) { // Bad lines contains the first 4 lines including the kotlinOptions section. - String badLines = ''; - final int startIndex = - gradleLines.indexOf(gradleLines.firstWhere(isKotlinOptions)); - for (int i = startIndex; - i < math.min(startIndex + 4, gradleLines.length); - i++) { + var badLines = ''; + final int startIndex = gradleLines.indexOf( + gradleLines.firstWhere(isKotlinOptions), + ); + for ( + var i = startIndex; + i < math.min(startIndex + 4, gradleLines.length); + i++ + ) { badLines += '${gradleLines[i]}\n'; } - final String kotlinErrorMessage = ''' + final kotlinErrorMessage = + ''' If build.gradle(.kts) sets jvmTarget then it must use JavaVersion syntax. Good: android { @@ -438,7 +517,8 @@ If build.gradle(.kts) sets jvmTarget then it must use JavaVersion syntax. $badLines '''; printError( - '$indentation${kotlinErrorMessage.split('\n').join('\n$indentation')}'); + '$indentation${kotlinErrorMessage.split('\n').join('\n$indentation')}', + ); return false; } // No error condition. @@ -446,12 +526,13 @@ If build.gradle(.kts) sets jvmTarget then it must use JavaVersion syntax. } bool _validateJavaKotlinCompileOptionsAlignment(List gradleLines) { - final List javaVersions = []; + final javaVersions = []; // Some java versions have the format VERSION_1_8 but we dont need to handle those // because they are below the minimum. - final RegExp javaVersionMatcher = - RegExp(r'JavaVersion.VERSION_(?\d+)'); - for (final String line in gradleLines) { + final javaVersionMatcher = RegExp( + r'JavaVersion.VERSION_(?\d+)', + ); + for (final line in gradleLines) { final RegExpMatch? match = javaVersionMatcher.firstMatch(line); if (!_isCommented(line) && match != null) { final String? foundVersion = match.namedGroup('javaVersion'); @@ -463,21 +544,24 @@ If build.gradle(.kts) sets jvmTarget then it must use JavaVersion syntax. if (javaVersions.isNotEmpty) { final int version = int.parse(javaVersions.first); if (!javaVersions.every((String element) => element == '$version')) { - const String javaVersionAlignmentError = ''' + const javaVersionAlignmentError = ''' If build.gradle(.kts) uses JavaVersion.* versions must be the same. '''; printError( - '$indentation${javaVersionAlignmentError.split('\n').join('\n$indentation')}'); + '$indentation${javaVersionAlignmentError.split('\n').join('\n$indentation')}', + ); return false; } if (version < _minimumJavaVersion) { - final String minimumJavaVersionError = ''' + final minimumJavaVersionError = + ''' build.gradle(.kts) uses "JavaVersion.VERSION_$version". Which is below the minimum required. Use at least "JavaVersion.VERSION_$_minimumJavaVersion". '''; printError( - '$indentation${minimumJavaVersionError.split('\n').join('\n$indentation')}'); + '$indentation${minimumJavaVersionError.split('\n').join('\n$indentation')}', + ); return false; } } @@ -489,19 +573,27 @@ Which is below the minimum required. Use at least "JavaVersion.VERSION_$_minimum /// Gradle-driven lints (those checked by ./gradlew lint) and treat them as /// errors. bool _validateGradleDrivenLintConfig( - RepositoryPackage package, List gradleLines) { + RepositoryPackage package, + List gradleLines, + ) { final List gradleBuildContents = package .platformDirectory(FlutterPlatform.android) .childFile('build.gradle') .readAsLinesSync(); - if (!gradleBuildContents.any((String line) => - line.contains('checkAllWarnings = true') && !_isCommented(line)) || - !gradleBuildContents.any((String line) => - line.contains('warningsAsErrors = true') && !_isCommented(line))) { - printError('${indentation}This package is not configured to enable all ' - 'Gradle-driven lint warnings and treat them as errors. ' - 'Please add the following to the lintOptions section of ' - 'android/build.gradle:'); + if (!gradleBuildContents.any( + (String line) => + line.contains('checkAllWarnings = true') && !_isCommented(line), + ) || + !gradleBuildContents.any( + (String line) => + line.contains('warningsAsErrors = true') && !_isCommented(line), + )) { + printError( + '${indentation}This package is not configured to enable all ' + 'Gradle-driven lint warnings and treat them as errors. ' + 'Please add the following to the lintOptions section of ' + 'android/build.gradle:', + ); print(''' checkAllWarnings = true warningsAsErrors = true @@ -512,28 +604,35 @@ Which is below the minimum required. Use at least "JavaVersion.VERSION_$_minimum } bool _validateCompileSdkUsage( - RepositoryPackage package, List gradleLines) { - final RegExp linePattern = RegExp(r'^\s*compileSdk.*\s+='); - final RegExp legacySettingPattern = RegExp(r'^\s*compileSdkVersion'); - final String? compileSdkLine = gradleLines - .firstWhereOrNull((String line) => linePattern.hasMatch(line)); + RepositoryPackage package, + List gradleLines, + ) { + final linePattern = RegExp(r'^\s*compileSdk.*\s+='); + final legacySettingPattern = RegExp(r'^\s*compileSdkVersion'); + final String? compileSdkLine = gradleLines.firstWhereOrNull( + (String line) => linePattern.hasMatch(line), + ); if (compileSdkLine == null) { // Equals regex not found check for method pattern. - final RegExp compileSpacePattern = RegExp(r'^\s*compileSdk'); + final compileSpacePattern = RegExp(r'^\s*compileSdk'); final String? methodAssignmentLine = gradleLines.firstWhereOrNull( - (String line) => compileSpacePattern.hasMatch(line)); + (String line) => compileSpacePattern.hasMatch(line), + ); if (methodAssignmentLine == null) { printError('${indentation}No compileSdk or compileSdkVersion found.'); } else { printError( - '${indentation}No "compileSdk =" found. Please use property assignment.'); + '${indentation}No "compileSdk =" found. Please use property assignment.', + ); } return false; } if (legacySettingPattern.hasMatch(compileSdkLine)) { - printError('${indentation}Please replace the deprecated ' - '"compileSdkVersion" setting with the newer "compileSdk"'); + printError( + '${indentation}Please replace the deprecated ' + '"compileSdkVersion" setting with the newer "compileSdk"', + ); return false; } if (compileSdkLine.contains('flutter.compileSdkVersion')) { @@ -542,38 +641,44 @@ Which is below the minimum required. Use at least "JavaVersion.VERSION_$_minimum pubspec.environment['flutter']; final Version? minFlutterVersion = flutterConstraint != null && flutterConstraint is VersionRange - ? flutterConstraint.min - : null; + ? flutterConstraint.min + : null; if (minFlutterVersion == null) { - printError('${indentation}Unable to find a Flutter SDK version ' - 'constraint. Use of flutter.compileSdkVersion requires a minimum ' - 'Flutter version of 3.27'); + printError( + '${indentation}Unable to find a Flutter SDK version ' + 'constraint. Use of flutter.compileSdkVersion requires a minimum ' + 'Flutter version of 3.27', + ); return false; } if (minFlutterVersion < Version(3, 27, 0)) { - printError('${indentation}Use of flutter.compileSdkVersion requires a ' - 'minimum Flutter version of 3.27, but this package currently ' - 'supports $minFlutterVersion.\n' - "${indentation}Please update the package's minimum Flutter SDK " - 'version to at least 3.27.'); + printError( + '${indentation}Use of flutter.compileSdkVersion requires a ' + 'minimum Flutter version of 3.27, but this package currently ' + 'supports $minFlutterVersion.\n' + "${indentation}Please update the package's minimum Flutter SDK " + 'version to at least 3.27.', + ); return false; } } else { // Extract compileSdkVersion and check if it is higher than flutter.compileSdkVersion. - final RegExp numericVersionPattern = RegExp(r'=\s*(\d+)'); - final RegExpMatch? versionMatch = - numericVersionPattern.firstMatch(compileSdkLine); + final numericVersionPattern = RegExp(r'=\s*(\d+)'); + final RegExpMatch? versionMatch = numericVersionPattern.firstMatch( + compileSdkLine, + ); if (versionMatch != null) { final int compileSdkVersion = int.parse(versionMatch.group(1)!); - const int minCompileSdkVersion = 36; + const minCompileSdkVersion = 36; if (compileSdkVersion < minCompileSdkVersion) { printError( - '${indentation}compileSdk version $compileSdkVersion is too low. ' - 'Minimum required version is $minCompileSdkVersion.\n' - "${indentation}Please update this package's compileSdkVersion to at least " - '$minCompileSdkVersion or use flutter.compileSdkVersion.'); + '${indentation}compileSdk version $compileSdkVersion is too low. ' + 'Minimum required version is $minCompileSdkVersion.\n' + "${indentation}Please update this package's compileSdkVersion to at least " + '$minCompileSdkVersion or use flutter.compileSdkVersion.', + ); return false; } } else { @@ -594,10 +699,15 @@ Which is below the minimum required. Use at least "JavaVersion.VERSION_$_minimum /// If [example]'s enclosing package is not a plugin package, this just /// returns true. bool _validateJavacLintConfig( - RepositoryPackage example, List gradleLines) { + RepositoryPackage example, + List gradleLines, + ) { final RepositoryPackage enclosingPackage = example.getEnclosingPackage()!; - if (!pluginSupportsPlatform(platformAndroid, enclosingPackage, - requiredMode: PlatformSupport.inline)) { + if (!pluginSupportsPlatform( + platformAndroid, + enclosingPackage, + requiredMode: PlatformSupport.inline, + )) { return true; } final String enclosingPackageName = enclosingPackage.directory.basename; @@ -605,16 +715,21 @@ Which is below the minimum required. Use at least "JavaVersion.VERSION_$_minimum // The check here is intentionally somewhat loose, to allow for the // possibility of variations (e.g., not using Xlint:all in some cases, or // passing other arguments). - if (!(gradleLines.any((String line) => - line.contains('project(":$enclosingPackageName")')) && - gradleLines.any((String line) => - line.contains('options.compilerArgs') && - line.contains('-Xlint') && - line.contains('-Werror')))) { - printError('The example ' - '"${getRelativePosixPath(example.directory, from: enclosingPackage.directory)}" ' - 'is not configured to treat javac lints and warnings as errors. ' - 'Please add the following to its build.gradle:'); + if (!(gradleLines.any( + (String line) => line.contains('project(":$enclosingPackageName")'), + ) && + gradleLines.any( + (String line) => + line.contains('options.compilerArgs') && + line.contains('-Xlint') && + line.contains('-Werror'), + ))) { + printError( + 'The example ' + '"${getRelativePosixPath(example.directory, from: enclosingPackage.directory)}" ' + 'is not configured to treat javac lints and warnings as errors. ' + 'Please add the following to its build.gradle:', + ); print(''' gradle.projectsEvaluated { project(":$enclosingPackageName") { @@ -632,19 +747,22 @@ gradle.projectsEvaluated { /// Validates whether the given [example] has its Kotlin version set to at /// least a minimum value, if it is set at all. bool _validateKotlinVersion( - RepositoryPackage example, List gradleLines) { - final RegExp kotlinVersionRegex = - RegExp(r"ext\.kotlin_version\s*=\s*'([\d.]+)'"); + RepositoryPackage example, + List gradleLines, + ) { + final kotlinVersionRegex = RegExp(r"ext\.kotlin_version\s*=\s*'([\d.]+)'"); RegExpMatch? match; if (gradleLines.any((String line) { match = kotlinVersionRegex.firstMatch(line); return match != null; })) { - final Version version = Version.parse(match!.group(1)!); + final version = Version.parse(match!.group(1)!); if (version < minKotlinVersion) { - printError('build.gradle sets "ext.kotlin_version" to "$version". The ' - 'minimum Kotlin version that can be specified is ' - '$minKotlinVersion, for compatibility with modern dependencies.'); + printError( + 'build.gradle sets "ext.kotlin_version" to "$version". The ' + 'minimum Kotlin version that can be specified is ' + '$minKotlinVersion, for compatibility with modern dependencies.', + ); return false; } } diff --git a/script/tool/lib/src/license_check_command.dart b/script/tool/lib/src/license_check_command.dart index f1659d3fb4d8..b5e8a365cf28 100644 --- a/script/tool/lib/src/license_check_command.dart +++ b/script/tool/lib/src/license_check_command.dart @@ -158,35 +158,45 @@ class LicenseCheckCommand extends PackageCommand { // separator, to do prefix matching with to test directory inclusion. final Iterable submodulePaths = (await _getSubmoduleDirectories()) .map( - (Directory dir) => '${dir.absolute.path}${platform.pathSeparator}'); + (Directory dir) => '${dir.absolute.path}${platform.pathSeparator}', + ); final Iterable allFiles = (await _getAllCheckedInFiles()).where( - (File file) => !submodulePaths.any(file.absolute.path.startsWith)); - - final Iterable codeFiles = allFiles.where((File file) => - _codeFileExtensions.contains(p.extension(file.path)) && - !_shouldIgnoreFile(file)); - final Iterable firstPartyLicenseFiles = allFiles.where((File file) => - path.basename(file.basename) == 'LICENSE' && !_isThirdParty(file)); - - final List licenseFileFailures = - await _checkLicenseFiles(firstPartyLicenseFiles); + (File file) => !submodulePaths.any(file.absolute.path.startsWith), + ); + + final Iterable codeFiles = allFiles.where( + (File file) => + _codeFileExtensions.contains(p.extension(file.path)) && + !_shouldIgnoreFile(file), + ); + final Iterable firstPartyLicenseFiles = allFiles.where( + (File file) => + path.basename(file.basename) == 'LICENSE' && !_isThirdParty(file), + ); + + final List licenseFileFailures = await _checkLicenseFiles( + firstPartyLicenseFiles, + ); final Map<_LicenseFailureType, List> codeFileFailures = await _checkCodeLicenses(codeFiles); - bool passed = true; + var passed = true; print('\n=======================================\n'); if (licenseFileFailures.isNotEmpty) { passed = false; printError( - 'The following LICENSE files do not follow the expected format:'); - for (final File file in licenseFileFailures) { + 'The following LICENSE files do not follow the expected format:', + ); + for (final file in licenseFileFailures) { printError(' ${_repoRelativePath(file)}'); } - printError('Please ensure that they use the exact format used in this ' - 'repository".\n'); + printError( + 'Please ensure that they use the exact format used in this ' + 'repository".\n', + ); } if (codeFileFailures[_LicenseFailureType.incorrectFirstParty]!.isNotEmpty) { @@ -197,22 +207,26 @@ class LicenseCheckCommand extends PackageCommand { printError(' ${_repoRelativePath(file)}'); } printError( - 'If this third-party code, move it to a "third_party/" directory, ' - 'otherwise ensure that you are using the exact copyright and license ' - 'text used by all first-party files in this repository.\n'); + 'If this third-party code, move it to a "third_party/" directory, ' + 'otherwise ensure that you are using the exact copyright and license ' + 'text used by all first-party files in this repository.\n', + ); } if (codeFileFailures[_LicenseFailureType.unknownThirdParty]!.isNotEmpty) { passed = false; printError( - 'No recognized license was found for the following third-party files:'); + 'No recognized license was found for the following third-party files:', + ); for (final File file in codeFileFailures[_LicenseFailureType.unknownThirdParty]!) { printError(' ${_repoRelativePath(file)}'); } - print('Please check that they have a license at the top of the file. ' - 'If they do, the license check needs to be updated to recognize ' - 'the new third-party license block.\n'); + print( + 'Please check that they have a license at the top of the file. ' + 'If they do, the license check needs to be updated to recognize ' + 'the new third-party license block.\n', + ); } if (!passed) { @@ -236,20 +250,20 @@ class LicenseCheckCommand extends PackageCommand { /// Checks all license blocks for [codeFiles], returning any that fail /// validation. Future>> _checkCodeLicenses( - Iterable codeFiles) async { - final List incorrectFirstPartyFiles = []; - final List unrecognizedThirdPartyFiles = []; + Iterable codeFiles, + ) async { + final incorrectFirstPartyFiles = []; + final unrecognizedThirdPartyFiles = []; // Most code file types in the repository use '//' comments. final String defaultFirstPartyLicenseBlock = _generateLicenseBlock('// '); // A few file types have a different comment structure. - final Map firstPartyLicenseBlockByExtension = - { + final firstPartyLicenseBlockByExtension = { '.sh': _generateLicenseBlock('# '), '.html': _generateLicenseBlock('', prefix: ''), }; - for (final File file in codeFiles) { + for (final file in codeFiles) { print('Checking ${_repoRelativePath(file)}'); // Some third-party directories have code that doesn't annotate each file, // so for those check the LICENSE file instead. This is done even though @@ -259,7 +273,8 @@ class LicenseCheckCommand extends PackageCommand { // a much worse failure mode. String content; if (_unannotatedFileThirdPartyDirectories.any( - (String dir) => file.path.contains('/third_party/packages/$dir/'))) { + (String dir) => file.path.contains('/third_party/packages/$dir/'), + )) { Directory packageDir = file.parent; while (packageDir.parent.basename != 'packages') { packageDir = packageDir.parent; @@ -274,12 +289,13 @@ class LicenseCheckCommand extends PackageCommand { final String firstPartyLicense = firstPartyLicenseBlockByExtension[p.extension(file.path)] ?? - defaultFirstPartyLicenseBlock; + defaultFirstPartyLicenseBlock; if (_isThirdParty(file)) { // Third-party directories allow either known third-party licenses, our // the first-party license, as there may be local additions. - if (!_thirdPartyLicenseBlockRegexes - .any((RegExp regex) => regex.hasMatch(content)) && + if (!_thirdPartyLicenseBlockRegexes.any( + (RegExp regex) => regex.hasMatch(content), + ) && !content.contains(firstPartyLicense)) { unrecognizedThirdPartyFiles.add(file); } @@ -303,9 +319,9 @@ class LicenseCheckCommand extends PackageCommand { /// Checks all provided LICENSE [files], returning any that fail validation. Future> _checkLicenseFiles(Iterable files) async { - final List incorrectLicenseFiles = []; + final incorrectLicenseFiles = []; - for (final File file in files) { + for (final file in files) { print('Checking ${_repoRelativePath(file)}'); // On Windows, git may auto-convert line endings on checkout; this should // still pass since they will be converted back on commit. @@ -340,8 +356,9 @@ class LicenseCheckCommand extends PackageCommand { Future> _getAllCheckedInFiles() async { final GitDir git = await gitDir; - final ProcessResult result = - await git.runCommand(['ls-files'], throwOnError: false); + final ProcessResult result = await git.runCommand([ + 'ls-files', + ], throwOnError: false); if (result.exitCode != 0) { printError('Unable to get list of files under source control'); throw ToolExit(_exitListFilesFailed); @@ -358,12 +375,13 @@ class LicenseCheckCommand extends PackageCommand { // Returns the directories containing mapped submodules, if any. Future> _getSubmoduleDirectories() async { - final List submodulePaths = []; - final Directory repoRoot = - packagesDir.fileSystem.directory((await gitDir).path); + final submodulePaths = []; + final Directory repoRoot = packagesDir.fileSystem.directory( + (await gitDir).path, + ); final File submoduleSpec = repoRoot.childFile('.gitmodules'); if (submoduleSpec.existsSync()) { - final RegExp pathLine = RegExp(r'path\s*=\s*(.*)'); + final pathLine = RegExp(r'path\s*=\s*(.*)'); for (final String line in submoduleSpec.readAsLinesSync()) { final RegExpMatch? match = pathLine.firstMatch(line); if (match != null) { @@ -375,8 +393,11 @@ class LicenseCheckCommand extends PackageCommand { } String _repoRelativePath(File file) { - return p.posix.joinAll(path.split( - path.relative(file.absolute.path, from: packagesDir.parent.path))); + return p.posix.joinAll( + path.split( + path.relative(file.absolute.path, from: packagesDir.parent.path), + ), + ); } } diff --git a/script/tool/lib/src/list_command.dart b/script/tool/lib/src/list_command.dart index c2d08f1857e8..6888fe5458f1 100644 --- a/script/tool/lib/src/list_command.dart +++ b/script/tool/lib/src/list_command.dart @@ -11,10 +11,7 @@ import 'common/repository_package.dart'; class ListCommand extends PackageCommand { /// Creates an instance of the list command, whose behavior depends on the /// 'type' argument it provides. - ListCommand( - super.packagesDir, { - super.platform, - }) { + ListCommand(super.packagesDir, {super.platform}) { argParser.addOption( _type, defaultsTo: _package, @@ -45,7 +42,8 @@ class ListCommand extends PackageCommand { case _example: final Stream examples = getTargetPackages() .expand( - (PackageEnumerationEntry entry) => entry.package.getExamples()); + (PackageEnumerationEntry entry) => entry.package.getExamples(), + ); await for (final RepositoryPackage package in examples) { print(package.path); } diff --git a/script/tool/lib/src/main.dart b/script/tool/lib/src/main.dart index 8bd58f07867c..61469157d193 100644 --- a/script/tool/lib/src/main.dart +++ b/script/tool/lib/src/main.dart @@ -42,12 +42,14 @@ import 'version_check_command.dart'; void main(List args) { const FileSystem fileSystem = LocalFileSystem(); - final Directory scriptDir = - fileSystem.file(io.Platform.script.toFilePath()).parent; + final Directory scriptDir = fileSystem + .file(io.Platform.script.toFilePath()) + .parent; // Support running either via directly invoking main.dart, or the wrapper in // bin/. - final Directory toolsDir = - scriptDir.basename == 'bin' ? scriptDir.parent : scriptDir.parent.parent; + final Directory toolsDir = scriptDir.basename == 'bin' + ? scriptDir.parent + : scriptDir.parent.parent; final Directory root = toolsDir.parent.parent; final Directory packagesDir = root.childDirectory('packages'); @@ -56,42 +58,44 @@ void main(List args) { io.exit(1); } - final CommandRunner commandRunner = CommandRunner( - 'dart pub global run flutter_plugin_tools', - 'Productivity utils for hosting multiple plugins within one repository.') - ..addCommand(AnalyzeCommand(packagesDir)) - ..addCommand(BuildExamplesCommand(packagesDir)) - ..addCommand(CreateAllPackagesAppCommand(packagesDir)) - ..addCommand(CustomTestCommand(packagesDir)) - ..addCommand(DependabotCheckCommand(packagesDir)) - ..addCommand(DriveExamplesCommand(packagesDir)) - ..addCommand(FederationSafetyCheckCommand(packagesDir)) - ..addCommand(FetchDepsCommand(packagesDir)) - ..addCommand(FirebaseTestLabCommand(packagesDir)) - ..addCommand(FixCommand(packagesDir)) - ..addCommand(FormatCommand(packagesDir)) - ..addCommand(GradleCheckCommand(packagesDir)) - ..addCommand(LicenseCheckCommand(packagesDir)) - ..addCommand(PodspecCheckCommand(packagesDir)) - ..addCommand(ListCommand(packagesDir)) - ..addCommand(NativeTestCommand(packagesDir)) - ..addCommand(MakeDepsPathBasedCommand(packagesDir)) - ..addCommand(PublishCheckCommand(packagesDir)) - ..addCommand(PublishCommand(packagesDir)) - ..addCommand(PubspecCheckCommand(packagesDir)) - ..addCommand(ReadmeCheckCommand(packagesDir)) - ..addCommand(RemoveDevDependenciesCommand(packagesDir)) - ..addCommand(RepoPackageInfoCheckCommand(packagesDir)) - ..addCommand(DartTestCommand(packagesDir)) - ..addCommand(UpdateDependencyCommand(packagesDir)) - ..addCommand(UpdateExcerptsCommand(packagesDir)) - ..addCommand(UpdateMinSdkCommand(packagesDir)) - ..addCommand(UpdateReleaseInfoCommand(packagesDir)) - ..addCommand(VersionCheckCommand(packagesDir)) - ..addCommand(BranchForBatchReleaseCommand(packagesDir)); + final commandRunner = + CommandRunner( + 'dart pub global run flutter_plugin_tools', + 'Productivity utils for hosting multiple plugins within one repository.', + ) + ..addCommand(AnalyzeCommand(packagesDir)) + ..addCommand(BuildExamplesCommand(packagesDir)) + ..addCommand(CreateAllPackagesAppCommand(packagesDir)) + ..addCommand(CustomTestCommand(packagesDir)) + ..addCommand(DependabotCheckCommand(packagesDir)) + ..addCommand(DriveExamplesCommand(packagesDir)) + ..addCommand(FederationSafetyCheckCommand(packagesDir)) + ..addCommand(FetchDepsCommand(packagesDir)) + ..addCommand(FirebaseTestLabCommand(packagesDir)) + ..addCommand(FixCommand(packagesDir)) + ..addCommand(FormatCommand(packagesDir)) + ..addCommand(GradleCheckCommand(packagesDir)) + ..addCommand(LicenseCheckCommand(packagesDir)) + ..addCommand(PodspecCheckCommand(packagesDir)) + ..addCommand(ListCommand(packagesDir)) + ..addCommand(NativeTestCommand(packagesDir)) + ..addCommand(MakeDepsPathBasedCommand(packagesDir)) + ..addCommand(PublishCheckCommand(packagesDir)) + ..addCommand(PublishCommand(packagesDir)) + ..addCommand(PubspecCheckCommand(packagesDir)) + ..addCommand(ReadmeCheckCommand(packagesDir)) + ..addCommand(RemoveDevDependenciesCommand(packagesDir)) + ..addCommand(RepoPackageInfoCheckCommand(packagesDir)) + ..addCommand(DartTestCommand(packagesDir)) + ..addCommand(UpdateDependencyCommand(packagesDir)) + ..addCommand(UpdateExcerptsCommand(packagesDir)) + ..addCommand(UpdateMinSdkCommand(packagesDir)) + ..addCommand(UpdateReleaseInfoCommand(packagesDir)) + ..addCommand(VersionCheckCommand(packagesDir)) + ..addCommand(BranchForBatchReleaseCommand(packagesDir)); commandRunner.run(args).catchError((Object e) { - final ToolExit toolExit = e as ToolExit; + final toolExit = e as ToolExit; int exitCode = toolExit.exitCode; // This should never happen; this check is here to guarantee that a ToolExit // never accidentally has code 0 thus causing CI to pass. diff --git a/script/tool/lib/src/make_deps_path_based_command.dart b/script/tool/lib/src/make_deps_path_based_command.dart index 304bb89d3b39..ed8119cb7c62 100644 --- a/script/tool/lib/src/make_deps_path_based_command.dart +++ b/script/tool/lib/src/make_deps_path_based_command.dart @@ -27,19 +27,19 @@ const int _exitPackageNotFound = 3; class MakeDepsPathBasedCommand extends PackageCommand { /// Creates an instance of the command to convert selected dependencies to /// path-based. - MakeDepsPathBasedCommand( - super.packagesDir, { - super.gitDir, - }) { - argParser.addMultiOption(_targetDependenciesArg, - help: - 'The names of the packages to convert to path-based dependencies.\n' - 'Ignored if --$_targetDependenciesWithNonBreakingUpdatesArg is ' - 'passed.', - valueHelp: 'some_package'); + MakeDepsPathBasedCommand(super.packagesDir, {super.gitDir}) { + argParser.addMultiOption( + _targetDependenciesArg, + help: + 'The names of the packages to convert to path-based dependencies.\n' + 'Ignored if --$_targetDependenciesWithNonBreakingUpdatesArg is ' + 'passed.', + valueHelp: 'some_package', + ); argParser.addFlag( _targetDependenciesWithNonBreakingUpdatesArg, - help: 'Causes all packages that have non-breaking version changes ' + help: + 'Causes all packages that have non-breaking version changes ' 'when compared against the git base to be treated as target ' 'packages.\n\nOnly packages with dependency constraints that allow ' 'the new version of a given target package will be updated. E.g., ' @@ -69,8 +69,9 @@ class MakeDepsPathBasedCommand extends PackageCommand { @override Future run() async { - final bool targetByVersion = - getBoolArg(_targetDependenciesWithNonBreakingUpdatesArg); + final bool targetByVersion = getBoolArg( + _targetDependenciesWithNonBreakingUpdatesArg, + ); final Set targetDependencies = targetByVersion ? await _getNonBreakingUpdatePackages() : getStringListArg(_targetDependenciesArg).toSet(); @@ -89,18 +90,20 @@ class MakeDepsPathBasedCommand extends PackageCommand { ? { for (final RepositoryPackage package in localDependencyPackages.values) - package.directory.basename: package.parsePubspec().version + package.directory.basename: package.parsePubspec().version, } : {}; final String repoRootPath = (await gitDir).path; for (final File pubspec in await _getAllPubspecs()) { final String displayPath = p.posix.joinAll( - path.split(path.relative(pubspec.absolute.path, from: repoRootPath))); + path.split(path.relative(pubspec.absolute.path, from: repoRootPath)), + ); final bool changed = await _addDependencyOverridesIfNecessary( - RepositoryPackage(pubspec.parent), - localDependencyPackages, - localPackageVersions); + RepositoryPackage(pubspec.parent), + localDependencyPackages, + localPackageVersions, + ); if (changed) { print(' Modified $displayPath'); } @@ -108,25 +111,28 @@ class MakeDepsPathBasedCommand extends PackageCommand { } Map _findLocalPackages(Set packageNames) { - final Map targets = - {}; - for (final String packageName in packageNames) { - final Directory topLevelCandidate = - packagesDir.childDirectory(packageName); + final targets = {}; + for (final packageName in packageNames) { + final Directory topLevelCandidate = packagesDir.childDirectory( + packageName, + ); // If packages// exists, then either that directory is the // package, or packages/// exists and is the // package (in the case of a federated plugin). if (topLevelCandidate.existsSync()) { - final Directory appFacingCandidate = - topLevelCandidate.childDirectory(packageName); - targets[packageName] = RepositoryPackage(appFacingCandidate.existsSync() - ? appFacingCandidate - : topLevelCandidate); + final Directory appFacingCandidate = topLevelCandidate.childDirectory( + packageName, + ); + targets[packageName] = RepositoryPackage( + appFacingCandidate.existsSync() + ? appFacingCandidate + : topLevelCandidate, + ); continue; } // Check for a match in the third-party packages directory. - final Directory thirdPartyCandidate = - thirdPartyPackagesDir.childDirectory(packageName); + final Directory thirdPartyCandidate = thirdPartyPackagesDir + .childDirectory(packageName); if (thirdPartyCandidate.existsSync()) { targets[packageName] = RepositoryPackage(thirdPartyCandidate); continue; @@ -136,8 +142,9 @@ class MakeDepsPathBasedCommand extends PackageCommand { // If it's the latter, it will be a directory whose name is a prefix. for (final FileSystemEntity entity in packagesDir.listSync()) { if (entity is Directory && packageName.startsWith(entity.basename)) { - final Directory subPackageCandidate = - entity.childDirectory(packageName); + final Directory subPackageCandidate = entity.childDirectory( + packageName, + ); if (subPackageCandidate.existsSync()) { targets[packageName] = RepositoryPackage(subPackageCandidate); break; @@ -180,24 +187,29 @@ class MakeDepsPathBasedCommand extends PackageCommand { } // Determine the dependencies to be overridden. - final Pubspec pubspec = Pubspec.parse(pubspecContents); + final pubspec = Pubspec.parse(pubspecContents); final Iterable combinedDependencies = [ // Filter out any dependencies with version constraint that wouldn't allow // the target if published, and anything that is already path-based. ...>[ - ...pubspec.dependencies.entries, - ...pubspec.devDependencies.entries, - ] - .where((MapEntry element) => - element.value is! PathDependency) - .where((MapEntry element) => - allowsVersion(element.value, versions[element.key])) + ...pubspec.dependencies.entries, + ...pubspec.devDependencies.entries, + ] + .where( + (MapEntry element) => + element.value is! PathDependency, + ) + .where( + (MapEntry element) => + allowsVersion(element.value, versions[element.key]), + ) .map((MapEntry entry) => entry.key), ...additionalPackagesToOverride, ]; final List packagesToOverride = combinedDependencies .where( - (String packageName) => localDependencies.containsKey(packageName)) + (String packageName) => localDependencies.containsKey(packageName), + ) .toList(); if (packagesToOverride.isEmpty) { @@ -208,19 +220,19 @@ class MakeDepsPathBasedCommand extends PackageCommand { final String repoRootPath = packagesDir.parent.path; final int packageDepth = path .split( - path.relative(package.directory.absolute.path, from: repoRootPath)) + path.relative(package.directory.absolute.path, from: repoRootPath), + ) .length; - final List relativeBasePathComponents = - List.filled(packageDepth, '..'); + final relativeBasePathComponents = List.filled(packageDepth, '..'); // Add the overrides. - final YamlEditor editablePubspec = YamlEditor(pubspecContents); + final editablePubspec = YamlEditor(pubspecContents); final YamlNode root = editablePubspec.parseAt([]); - const String dependencyOverridesKey = 'dependency_overrides'; + const dependencyOverridesKey = 'dependency_overrides'; // Add in any existing overrides, then sort the combined list to avoid // sort_pub_dependencies lint violations. - final YamlMap? existingOverrides = + final existingOverrides = (root as YamlMap)[dependencyOverridesKey] as YamlMap?; final List allDependencyOverrides = { ...existingOverrides?.keys.cast() ?? [], @@ -235,16 +247,19 @@ class MakeDepsPathBasedCommand extends PackageCommand { // failures. // This uses string concatenation rather than YamlMap because the latter // doesn't guarantee any particular output order for its entries. - final List newOverrideLines = []; - for (final String packageName in allDependencyOverrides) { + final newOverrideLines = []; + for (final packageName in allDependencyOverrides) { final String overrideValue; if (packagesToOverride.contains(packageName)) { // Create a new override. // Find the relative path from the common base to the local package. final List repoRelativePathComponents = path.split( - path.relative(localDependencies[packageName]!.path, - from: repoRootPath)); + path.relative( + localDependencies[packageName]!.path, + from: repoRootPath, + ), + ); final String pathValue = p.posix.joinAll([ ...relativeBasePathComponents, ...repoRelativePathComponents, @@ -258,19 +273,21 @@ class MakeDepsPathBasedCommand extends PackageCommand { } // Create an empty section as a placeholder to replace. editablePubspec.update([dependencyOverridesKey], YamlMap()); - String newContent = editablePubspec.toString(); + var newContent = editablePubspec.toString(); // Add the warning if it's not already there. - final String warningComment = + final warningComment = newContent.contains(_dependencyOverrideWarningComment) - ? '' - : '$_dependencyOverrideWarningComment\n'; + ? '' + : '$_dependencyOverrideWarningComment\n'; // Replace the placeholder with the new section. - newContent = - newContent.replaceFirst(RegExp('$dependencyOverridesKey:\\s*{}\\n'), ''' + newContent = newContent.replaceFirst( + RegExp('$dependencyOverridesKey:\\s*{}\\n'), + ''' $warningComment$dependencyOverridesKey: ${newOverrideLines.join('\n')} -'''); +''', + ); // Write the new pubspec. package.pubspecFile.writeAsStringSync(newContent); @@ -282,8 +299,11 @@ ${newOverrideLines.join('\n')} // it needs the overrides in order for tests to pass. for (final RepositoryPackage example in package.getExamples()) { await _addDependencyOverridesIfNecessary( - example, localDependencies, versions, - additionalPackagesToOverride: packagesToOverride); + example, + localDependencies, + versions, + additionalPackagesToOverride: packagesToOverride, + ); } return true; @@ -292,8 +312,10 @@ ${newOverrideLines.join('\n')} /// Returns all pubspecs anywhere under the packages directory. Future> _getAllPubspecs() => packagesDir.parent .list(recursive: true, followLinks: false) - .where((FileSystemEntity entity) => - entity is File && p.basename(entity.path) == 'pubspec.yaml') + .where( + (FileSystemEntity entity) => + entity is File && p.basename(entity.path) == 'pubspec.yaml', + ) .map((FileSystemEntity file) => file as File) .toList(); @@ -307,7 +329,7 @@ ${newOverrideLines.join('\n')} final String baseSha = await gitVersionFinder.getBaseSha(); print('Finding changed packages relative to "$baseSha"...'); - final Set changedPackages = {}; + final changedPackages = {}; for (final String changedPath in await gitVersionFinder.getChangedFiles()) { // Git output always uses Posix paths. final List allComponents = p.posix.split(changedPath); @@ -320,13 +342,19 @@ ${newOverrideLines.join('\n')} print(' Skipping $changedPath; not in packages directory.'); continue; } - final RepositoryPackage package = - RepositoryPackage(packagesDir.fileSystem.file(changedPath).parent); + final package = RepositoryPackage( + packagesDir.fileSystem.file(changedPath).parent, + ); // Ignored deleted packages, as they won't be published. if (!package.pubspecFile.existsSync()) { - final String directoryName = p.posix.joinAll(path.split(path.relative( - package.directory.absolute.path, - from: packagesDir.parent.path))); + final String directoryName = p.posix.joinAll( + path.split( + path.relative( + package.directory.absolute.path, + from: packagesDir.parent.path, + ), + ), + ); print(' Skipping $directoryName; deleted.'); continue; } @@ -348,12 +376,18 @@ ${newOverrideLines.join('\n')} return false; } - final String pubspecGitPath = p.posix.joinAll(path.split(path.relative( - package.pubspecFile.absolute.path, - from: (await gitDir).path))); + final String pubspecGitPath = p.posix.joinAll( + path.split( + path.relative( + package.pubspecFile.absolute.path, + from: (await gitDir).path, + ), + ), + ); final GitVersionFinder gitVersionFinder = await retrieveVersionFinder(); - final Version? previousVersion = - await gitVersionFinder.getPackageVersion(pubspecGitPath); + final Version? previousVersion = await gitVersionFinder.getPackageVersion( + pubspecGitPath, + ); if (previousVersion == null) { // The plugin is new, so nothing can be depending on it yet. return false; diff --git a/script/tool/lib/src/native_test_command.dart b/script/tool/lib/src/native_test_command.dart index 4c2efd8d4ae1..a944b95b87bc 100644 --- a/script/tool/lib/src/native_test_command.dart +++ b/script/tool/lib/src/native_test_command.dart @@ -49,11 +49,12 @@ class NativeTestCommand extends PackageLoopingCommand { super.platform, super.gitDir, Abi? abi, - }) : _abi = abi ?? Abi.current(), - _xcode = Xcode(processRunner: processRunner, log: true) { + }) : _abi = abi ?? Abi.current(), + _xcode = Xcode(processRunner: processRunner, log: true) { argParser.addOption( _iOSDestinationFlag, - help: 'Specify the destination when running iOS tests.\n' + help: + 'Specify the destination when running iOS tests.\n' 'This is passed to the `-destination` argument in the xcodebuild command.\n' 'See https://developer.apple.com/library/archive/technotes/tn2339/_index.html#//apple_ref/doc/uid/DTS40014588-CH1-UNIT ' 'for details on how to specify the destination.', @@ -66,14 +67,21 @@ class NativeTestCommand extends PackageLoopingCommand { // By default, both unit tests and integration tests are run, but provide // flags to disable one or the other. - argParser.addFlag(_unitTestFlag, - help: 'Runs native unit tests', defaultsTo: true); - argParser.addFlag(_integrationTestFlag, - help: 'Runs native integration (UI) tests', defaultsTo: true); + argParser.addFlag( + _unitTestFlag, + help: 'Runs native unit tests', + defaultsTo: true, + ); + argParser.addFlag( + _integrationTestFlag, + help: 'Runs native integration (UI) tests', + defaultsTo: true, + ); argParser.addMultiOption( _xcodeWarningsExceptionsFlag, - help: 'A list of packages that are allowed to have Xcode warnings.\n\n' + help: + 'A list of packages that are allowed to have Xcode warnings.\n\n' 'Alternately, a list of one or more YAML files that contain a list ' 'of packages to allow Xcode warnings.', defaultsTo: [], @@ -147,31 +155,32 @@ this command. } if (getBoolArg(platformWindows) && getBoolArg(_integrationTestFlag)) { - logWarning('This command currently only supports unit tests for Windows. ' - 'See https://github.com/flutter/flutter/issues/70233.'); + logWarning( + 'This command currently only supports unit tests for Windows. ' + 'See https://github.com/flutter/flutter/issues/70233.', + ); } if (getBoolArg(platformLinux) && getBoolArg(_integrationTestFlag)) { - logWarning('This command currently only supports unit tests for Linux. ' - 'See https://github.com/flutter/flutter/issues/70235.'); + logWarning( + 'This command currently only supports unit tests for Linux. ' + 'See https://github.com/flutter/flutter/issues/70235.', + ); } // iOS-specific run-level state. if (_requestedPlatforms.contains('ios')) { String destination = getStringArg(_iOSDestinationFlag); if (destination.isEmpty) { - final String? simulatorId = - await _xcode.findBestAvailableIphoneSimulator(); + final String? simulatorId = await _xcode + .findBestAvailableIphoneSimulator(); if (simulatorId == null) { printError('Cannot find any available iOS simulators.'); throw ToolExit(_exitNoIOSSimulators); } destination = 'id=$simulatorId'; } - _iOSDestinationFlags = [ - '-destination', - destination, - ]; + _iOSDestinationFlags = ['-destination', destination]; } _xcodeWarningsExceptions = getYamlListArg(_xcodeWarningsExceptionsFlag); @@ -179,10 +188,13 @@ this command. @override Future runForPackage(RepositoryPackage package) async { - final List testPlatforms = []; + final testPlatforms = []; for (final String platform in _requestedPlatforms) { - if (!pluginSupportsPlatform(platform, package, - requiredMode: PlatformSupport.inline)) { + if (!pluginSupportsPlatform( + platform, + package, + requiredMode: PlatformSupport.inline, + )) { print('No implementation for ${_platforms[platform]!.label}.'); continue; } @@ -197,20 +209,22 @@ this command. return PackageResult.skip('Nothing to test for target platform(s).'); } - final _TestMode mode = _TestMode( + final mode = _TestMode( unit: getBoolArg(_unitTestFlag), integration: getBoolArg(_integrationTestFlag), ); - bool ranTests = false; - bool failed = false; - final List failureMessages = []; - for (final String platform in testPlatforms) { + var ranTests = false; + var failed = false; + final failureMessages = []; + for (final platform in testPlatforms) { final _PlatformDetails platformInfo = _platforms[platform]!; print('Running tests for ${platformInfo.label}...'); print('----------------------------------------'); - final _PlatformResult result = - await platformInfo.testFunction(package, mode); + final _PlatformResult result = await platformInfo.testFunction( + package, + mode, + ); ranTests |= result.state != RunState.skipped; if (result.state == RunState.failed) { failed = true; @@ -219,9 +233,11 @@ this command. // Only provide the failing platforms in the failure details if testing // multiple platforms, otherwise it's just noise. if (_requestedPlatforms.length > 1) { - failureMessages.add(error != null - ? '${platformInfo.label}: $error' - : platformInfo.label); + failureMessages.add( + error != null + ? '${platformInfo.label}: $error' + : platformInfo.label, + ); } else if (error != null) { // If there's only one platform, only provide error details in the // summary if the platform returned a message. @@ -239,7 +255,9 @@ this command. } Future<_PlatformResult> _testAndroid( - RepositoryPackage plugin, _TestMode mode) async { + RepositoryPackage plugin, + _TestMode mode, + ) async { bool exampleHasUnitTests(RepositoryPackage example) { return example .platformDirectory(FlutterPlatform.android) @@ -257,14 +275,19 @@ this command. _JavaTestInfo getJavaTestInfo(File testFile) { final List contents = testFile.readAsLinesSync(); return _JavaTestInfo( - usesFlutterTestRunner: contents.any((String line) => - line.trimLeft().startsWith('@RunWith(FlutterTestRunner.class)')), - hasDartIntegrationTestAnnotation: contents.any((String line) => - line.trimLeft().startsWith('@DartIntegrationTest'))); + usesFlutterTestRunner: contents.any( + (String line) => + line.trimLeft().startsWith('@RunWith(FlutterTestRunner.class)'), + ), + hasDartIntegrationTestAnnotation: contents.any( + (String line) => line.trimLeft().startsWith('@DartIntegrationTest'), + ), + ); } Map findIntegrationTestFiles( - RepositoryPackage example) { + RepositoryPackage example, + ) { final Directory integrationTestDirectory = example .platformDirectory(FlutterPlatform.android) .childDirectory('app') @@ -289,33 +312,34 @@ this command. .listSync(recursive: true) .whereType() .where((File file) { - final String basename = file.basename; - return basename != 'DartIntegrationTest.java' && - basename != 'DartIntegrationTest.kt'; - }); + final String basename = file.basename; + return basename != 'DartIntegrationTest.java' && + basename != 'DartIntegrationTest.kt'; + }); return { for (final File file in integrationTestFiles) - file: getJavaTestInfo(file) + file: getJavaTestInfo(file), }; } final Iterable examples = plugin.getExamples(); final String pluginName = plugin.directory.basename; - bool ranUnitTests = false; - bool ranAnyTests = false; - bool failed = false; - bool hasMisconfiguredIntegrationTest = false; + var ranUnitTests = false; + var ranAnyTests = false; + var failed = false; + var hasMisconfiguredIntegrationTest = false; // Iterate through all examples (in the rare case that there is more than // one example); running any tests found for each one. Requirements on what // tests are present are enforced at the overall package level, not a per- // example level. E.g., it's fine for only one example to have unit tests. - for (final RepositoryPackage example in examples) { + for (final example in examples) { final bool hasUnitTests = exampleHasUnitTests(example); final Map candidateIntegrationTestFiles = findIntegrationTestFiles(example); - final bool hasIntegrationTests = candidateIntegrationTestFiles.values - .any((_JavaTestInfo info) => !info.hasDartIntegrationTestAnnotation); + final bool hasIntegrationTests = candidateIntegrationTestFiles.values.any( + (_JavaTestInfo info) => !info.hasDartIntegrationTestAnnotation, + ); if (mode.unit && !hasUnitTests) { _printNoExampleTestsMessage(example, 'Android unit'); @@ -333,7 +357,7 @@ this command. final String exampleName = example.displayName; _printRunningExampleTestsMessage(example, 'Android'); - final GradleProject project = GradleProject( + final project = GradleProject( example, processRunner: processRunner, platform: platform, @@ -354,15 +378,17 @@ this command. if (runUnitTests) { print('Running unit tests...'); - const String taskName = 'testDebugUnitTest'; + const taskName = 'testDebugUnitTest'; // Target the unit tests in the app and plugin specifically, to avoid // transitively running tests in dependencies. If unit tests have // already run in an earlier example, only run any app-level unit tests. - final List pluginTestTask = [ - if (!ranUnitTests) '$pluginName:$taskName' + final pluginTestTask = [ + if (!ranUnitTests) '$pluginName:$taskName', ]; - final int exitCode = await project.runCommand('app:$taskName', - additionalTasks: pluginTestTask); + final int exitCode = await project.runCommand( + 'app:$taskName', + additionalTasks: pluginTestTask, + ); if (exitCode != 0) { printError('$exampleName unit tests failed.'); failed = true; @@ -378,9 +404,11 @@ this command. // filtering them out. final List misconfiguredTestFiles = candidateIntegrationTestFiles .entries - .where((MapEntry entry) => - entry.value.usesFlutterTestRunner && - !entry.value.hasDartIntegrationTestAnnotation) + .where( + (MapEntry entry) => + entry.value.usesFlutterTestRunner && + !entry.value.hasDartIntegrationTestAnnotation, + ) .map((MapEntry entry) => entry.key) .toList(); if (misconfiguredTestFiles.isEmpty) { @@ -388,19 +416,14 @@ this command. // tests directly, but there doesn't seem to be a way to filter based // on annotation contents, so the DartIntegrationTest annotation was // created as a proxy for that. - const String filter = - 'notAnnotation=io.flutter.plugins.DartIntegrationTest'; + const filter = 'notAnnotation=io.flutter.plugins.DartIntegrationTest'; print('Running integration tests...'); // Explicitly request all ABIs, as Flutter would if being called // without a specific target (see // https://github.com/flutter/flutter/pull/154476) to ensure it can // run on any architecture emulator. - const List abis = [ - 'android-arm', - 'android-arm64', - 'android-x64', - ]; + const abis = ['android-arm', 'android-arm64', 'android-x64']; final int exitCode = await project.runCommand( 'app:connectedAndroidTest', arguments: [ @@ -415,8 +438,10 @@ this command. ranAnyTests = true; } else { hasMisconfiguredIntegrationTest = true; - printError('$misconfiguredJavaIntegrationTestErrorExplanation\n' - '${misconfiguredTestFiles.map((File f) => ' ${f.path}').join('\n')}'); + printError( + '$misconfiguredJavaIntegrationTestErrorExplanation\n' + '${misconfiguredTestFiles.map((File f) => ' ${f.path}').join('\n')}', + ); } } } @@ -425,13 +450,17 @@ this command. return _PlatformResult(RunState.failed); } if (hasMisconfiguredIntegrationTest) { - return _PlatformResult(RunState.failed, - error: 'Misconfigured integration test.'); + return _PlatformResult( + RunState.failed, + error: 'Misconfigured integration test.', + ); } if (!mode.integrationOnly && !ranUnitTests) { printError('No unit tests ran. Plugins are required to have unit tests.'); - return _PlatformResult(RunState.failed, - error: 'No unit tests ran (use --exclude if this is intentional).'); + return _PlatformResult( + RunState.failed, + error: 'No unit tests ran (use --exclude if this is intentional).', + ); } if (!ranAnyTests) { return _PlatformResult(RunState.skipped); @@ -440,8 +469,12 @@ this command. } Future<_PlatformResult> _testIOS(RepositoryPackage plugin, _TestMode mode) { - return _runXcodeTests(plugin, FlutterPlatform.ios, mode, - extraFlags: _iOSDestinationFlags); + return _runXcodeTests( + plugin, + FlutterPlatform.ios, + mode, + extraFlags: _iOSDestinationFlags, + ); } Future<_PlatformResult> _testMacOS(RepositoryPackage plugin, _TestMode mode) { @@ -460,16 +493,17 @@ this command. List extraFlags = const [], }) async { String? testTarget; - const String unitTestTarget = 'RunnerTests'; + const unitTestTarget = 'RunnerTests'; if (mode.unitOnly) { testTarget = unitTestTarget; } else if (mode.integrationOnly) { testTarget = 'RunnerUITests'; } - final String targetPlatformString = - targetPlatform == FlutterPlatform.ios ? 'iOS' : 'macOS'; + final targetPlatformString = targetPlatform == FlutterPlatform.ios + ? 'iOS' + : 'macOS'; - bool ranUnitTests = false; + var ranUnitTests = false; // Assume skipped until at least one test has run. RunState overallResult = RunState.skipped; for (final RepositoryPackage example in plugin.getExamples()) { @@ -478,15 +512,17 @@ this command. // If running a specific target, check that. Otherwise, check if there // are unit tests, since having no unit tests for a plugin is fatal // (by repo policy) even if there are integration tests. - bool exampleHasUnitTests = false; + var exampleHasUnitTests = false; final String? targetToCheck = testTarget ?? (mode.unit ? unitTestTarget : null); final Directory xcodeProject = example .platformDirectory(targetPlatform) .childDirectory('Runner.xcodeproj'); if (targetToCheck != null) { - final bool? hasTarget = - await _xcode.projectHasTarget(xcodeProject, targetToCheck); + final bool? hasTarget = await _xcode.projectHasTarget( + xcodeProject, + targetToCheck, + ); if (hasTarget == null) { printError('Unable to check targets for $exampleName.'); overallResult = RunState.failed; @@ -534,13 +570,14 @@ this command. ); // The exit code from 'xcodebuild test' when there are no tests. - const int xcodebuildNoTestExitCode = 66; + const xcodebuildNoTestExitCode = 66; switch (exitCode) { case xcodebuildNoTestExitCode: _printNoExampleTestsMessage(example, targetPlatformString); case 0: printSuccess( - 'Successfully ran $targetPlatformString xctest for $exampleName'); + 'Successfully ran $targetPlatformString xctest for $exampleName', + ); // If this is the first test, assume success until something fails. if (overallResult == RunState.skipped) { overallResult = RunState.succeeded; @@ -564,8 +601,10 @@ this command. // tests if there weren't also failures, to avoid having a misleadingly // specific message. if (overallResult != RunState.failed) { - return _PlatformResult(RunState.failed, - error: 'No unit tests ran (use --exclude if this is intentional).'); + return _PlatformResult( + RunState.failed, + error: 'No unit tests ran (use --exclude if this is intentional).', + ); } } @@ -573,7 +612,9 @@ this command. } Future<_PlatformResult> _testWindows( - RepositoryPackage plugin, _TestMode mode) async { + RepositoryPackage plugin, + _TestMode mode, + ) async { if (mode.integrationOnly) { return _PlatformResult(RunState.skipped); } @@ -583,12 +624,18 @@ this command. file.basename.endsWith('_tests.exe'); } - return _runGoogleTestTests(plugin, 'Windows', 'Debug', - isTestBinary: isTestBinary); + return _runGoogleTestTests( + plugin, + 'Windows', + 'Debug', + isTestBinary: isTestBinary, + ); } Future<_PlatformResult> _testLinux( - RepositoryPackage plugin, _TestMode mode) async { + RepositoryPackage plugin, + _TestMode mode, + ) async { if (mode.integrationOnly) { return _PlatformResult(RunState.skipped); } @@ -606,8 +653,12 @@ this command. // generate build files without doing a build, and using that instead of // relying on running build-examples. See // https://github.com/flutter/flutter/issues/93407. - return _runGoogleTestTests(plugin, 'Linux', 'Release', - isTestBinary: isTestBinary); + return _runGoogleTestTests( + plugin, + 'Linux', + 'Release', + isTestBinary: isTestBinary, + ); } /// Finds every file in the relevant (based on [platformName], [buildMode], @@ -623,12 +674,12 @@ this command. String buildMode, { required bool Function(File) isTestBinary, }) async { - final List testBinaries = []; - bool hasMissingBuild = false; - bool buildFailed = false; + final testBinaries = []; + var hasMissingBuild = false; + var buildFailed = false; String? arch; - const String x64DirName = 'x64'; - const String arm64DirName = 'arm64'; + const x64DirName = 'x64'; + const arm64DirName = 'arm64'; if (platform.isWindows) { arch = _abi == Abi.windowsX64 ? x64DirName : arm64DirName; } else if (platform.isLinux) { @@ -637,38 +688,46 @@ this command. arch = 'x64'; } for (final RepositoryPackage example in plugin.getExamples()) { - CMakeProject project = CMakeProject(example.directory, - buildMode: buildMode, - processRunner: processRunner, - platform: platform, - arch: arch); + var project = CMakeProject( + example.directory, + buildMode: buildMode, + processRunner: processRunner, + platform: platform, + arch: arch, + ); if (platform.isWindows) { if (arch == arm64DirName && !project.isConfigured()) { // Check for x64, to handle builds newer than 3.13, but that don't yet // have https://github.com/flutter/flutter/issues/129807. // TODO(stuartmorgan): Remove this when CI no longer supports a // version of Flutter without the issue above fixed. - project = CMakeProject(example.directory, - buildMode: buildMode, - processRunner: processRunner, - platform: platform, - arch: x64DirName); + project = CMakeProject( + example.directory, + buildMode: buildMode, + processRunner: processRunner, + platform: platform, + arch: x64DirName, + ); } if (!project.isConfigured()) { // Check again without the arch subdirectory, since 3.13 doesn't // have it yet. // TODO(stuartmorgan): Remove this when CI no longer supports Flutter // 3.13. - project = CMakeProject(example.directory, - buildMode: buildMode, - processRunner: processRunner, - platform: platform); + project = CMakeProject( + example.directory, + buildMode: buildMode, + processRunner: processRunner, + platform: platform, + ); } } if (!project.isConfigured()) { - printError('ERROR: Run "flutter build" on ${example.displayName}, ' - 'or run this tool\'s "build-examples" command, for the target ' - 'platform before executing tests.'); + printError( + 'ERROR: Run "flutter build" on ${example.displayName}, ' + 'or run this tool\'s "build-examples" command, for the target ' + 'platform before executing tests.', + ); hasMissingBuild = true; continue; } @@ -682,43 +741,54 @@ this command. buildFailed = true; } - testBinaries.addAll(project.buildDirectory - .listSync(recursive: true) - .whereType() - .where(isTestBinary) - .where((File file) { - // Only run the `buildMode` build of the unit tests, to avoid running - // the same tests multiple times. - final List components = path.split(file.path); - return components.contains(buildMode) || - components.contains(buildMode.toLowerCase()); - })); + testBinaries.addAll( + project.buildDirectory + .listSync(recursive: true) + .whereType() + .where(isTestBinary) + .where((File file) { + // Only run the `buildMode` build of the unit tests, to avoid running + // the same tests multiple times. + final List components = path.split(file.path); + return components.contains(buildMode) || + components.contains(buildMode.toLowerCase()); + }), + ); } if (hasMissingBuild) { - return _PlatformResult(RunState.failed, - error: 'Examples must be built before testing.'); + return _PlatformResult( + RunState.failed, + error: 'Examples must be built before testing.', + ); } if (buildFailed) { - return _PlatformResult(RunState.failed, - error: 'Failed to build $platformName unit tests.'); + return _PlatformResult( + RunState.failed, + error: 'Failed to build $platformName unit tests.', + ); } if (testBinaries.isEmpty) { - final String binaryExtension = platform.isWindows ? '.exe' : ''; + final binaryExtension = platform.isWindows ? '.exe' : ''; printError( - 'No test binaries found. At least one *_test(s)$binaryExtension ' - 'binary should be built by the example(s)'); - return _PlatformResult(RunState.failed, - error: 'No $platformName unit tests found'); + 'No test binaries found. At least one *_test(s)$binaryExtension ' + 'binary should be built by the example(s)', + ); + return _PlatformResult( + RunState.failed, + error: 'No $platformName unit tests found', + ); } - bool passing = true; - for (final File test in testBinaries) { + var passing = true; + for (final test in testBinaries) { print('Running ${test.basename}...'); - final int exitCode = - await processRunner.runAndStream(test.path, []); + final int exitCode = await processRunner.runAndStream( + test.path, + [], + ); passing &= exitCode == 0; } return _PlatformResult(passing ? RunState.succeeded : RunState.failed); @@ -727,7 +797,9 @@ this command. /// Prints a standard format message indicating that [platform] tests for /// [plugin]'s [example] are about to be run. void _printRunningExampleTestsMessage( - RepositoryPackage example, String platform) { + RepositoryPackage example, + String platform, + ) { print('Running $platform tests for ${example.displayName}...'); } @@ -740,15 +812,12 @@ this command. // The type for a function that takes a plugin directory and runs its native // tests for a specific platform. -typedef _TestFunction = Future<_PlatformResult> Function( - RepositoryPackage, _TestMode); +typedef _TestFunction = + Future<_PlatformResult> Function(RepositoryPackage, _TestMode); /// A collection of information related to a specific platform. class _PlatformDetails { - const _PlatformDetails( - this.label, - this.testFunction, - ); + const _PlatformDetails(this.label, this.testFunction); /// The name to use in output. final String label; @@ -786,9 +855,10 @@ class _PlatformResult { /// The state of a .java test file. class _JavaTestInfo { - const _JavaTestInfo( - {required this.usesFlutterTestRunner, - required this.hasDartIntegrationTestAnnotation}); + const _JavaTestInfo({ + required this.usesFlutterTestRunner, + required this.hasDartIntegrationTestAnnotation, + }); /// Whether the test class uses the FlutterTestRunner. final bool usesFlutterTestRunner; diff --git a/script/tool/lib/src/podspec_check_command.dart b/script/tool/lib/src/podspec_check_command.dart index e768a5168c50..24f0d80f3461 100644 --- a/script/tool/lib/src/podspec_check_command.dart +++ b/script/tool/lib/src/podspec_check_command.dart @@ -61,14 +61,14 @@ class PodspecCheckCommand extends PackageLoopingCommand { @override Future runForPackage(RepositoryPackage package) async { - final List errors = []; + final errors = []; final List podspecs = await _podspecsToLint(package); if (podspecs.isEmpty) { return PackageResult.skip('No podspecs.'); } - for (final File podspec in podspecs) { + for (final podspec in podspecs) { if (!await _lintPodspec(podspec)) { errors.add(podspec.basename); } @@ -76,21 +76,25 @@ class PodspecCheckCommand extends PackageLoopingCommand { if (await _hasIOSSwiftCode(package)) { print('iOS Swift code found, checking for search paths settings...'); - for (final File podspec in podspecs) { + for (final podspec in podspecs) { if (_isPodspecMissingSearchPaths(podspec)) { - const String workaroundBlock = r''' + const workaroundBlock = r''' s.xcconfig = { 'LIBRARY_SEARCH_PATHS' => '$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)/ $(SDKROOT)/usr/lib/swift', 'LD_RUNPATH_SEARCH_PATHS' => '/usr/lib/swift', } '''; - final String path = - getRelativePosixPath(podspec, from: package.directory); - printError('$path is missing search path configuration. Any iOS ' - 'plugin implementation that contains Swift implementation code ' - 'needs to contain the following:\n\n' - '$workaroundBlock\n' - 'For more details, see https://github.com/flutter/flutter/issues/118418.'); + final String path = getRelativePosixPath( + podspec, + from: package.directory, + ); + printError( + '$path is missing search path configuration. Any iOS ' + 'plugin implementation that contains Swift implementation code ' + 'needs to contain the following:\n\n' + '$workaroundBlock\n' + 'For more details, see https://github.com/flutter/flutter/issues/118418.', + ); errors.add(podspec.basename); } } @@ -99,9 +103,11 @@ class PodspecCheckCommand extends PackageLoopingCommand { if ((pluginSupportsPlatform(platformIOS, package) || pluginSupportsPlatform(platformMacOS, package)) && !podspecs.any(_hasPrivacyManifest)) { - printError('No PrivacyInfo.xcprivacy file specified. Please ensure that ' - 'a privacy manifest is included in the build using ' - '`resource_bundles`'); + printError( + 'No PrivacyInfo.xcprivacy file specified. Please ensure that ' + 'a privacy manifest is included in the build using ' + '`resource_bundles`', + ); errors.add('No privacy manifest'); } @@ -111,8 +117,9 @@ class PodspecCheckCommand extends PackageLoopingCommand { } Future> _podspecsToLint(RepositoryPackage package) async { - final List podspecs = - await getFilesForPackage(package).where((File entity) { + final List podspecs = await getFilesForPackage(package).where(( + File entity, + ) { final String filename = entity.basename; return path.extension(filename) == '.podspec' && filename != 'Flutter.podspec' && @@ -135,16 +142,16 @@ class PodspecCheckCommand extends PackageLoopingCommand { } Future _runPodLint(String podspecPath) async { - final List arguments = [ - 'lib', - 'lint', - podspecPath, - '--quick', - ]; + final arguments = ['lib', 'lint', podspecPath, '--quick']; print('Running "pod ${arguments.join(' ')}"'); - return processRunner.run('pod', arguments, - workingDir: packagesDir, stdoutEncoding: utf8, stderrEncoding: utf8); + return processRunner.run( + 'pod', + arguments, + workingDir: packagesDir, + stdoutEncoding: utf8, + stderrEncoding: utf8, + ); } /// Returns true if there is any iOS plugin implementation code written in @@ -162,8 +169,10 @@ class PodspecCheckCommand extends PackageLoopingCommand { .childFile('Package.swift') .path; return getFilesForPackage(package).any((File entity) { - final String relativePath = - getRelativePosixPath(entity, from: package.directory); + final String relativePath = getRelativePosixPath( + entity, + from: package.directory, + ); // Ignore example code. if (relativePath.startsWith('example/')) { return false; @@ -200,7 +209,7 @@ class PodspecCheckCommand extends PackageLoopingCommand { // This errs on the side of being too strict, to minimize the chance of // accidental incorrect configuration. If we ever need more flexibility // due to a false negative we can adjust this as necessary. - final RegExp workaround = RegExp(r''' + final workaround = RegExp(r''' \s*s\.(?:ios\.)?xcconfig = {[^}]* \s*'LIBRARY_SEARCH_PATHS' => '\$\(TOOLCHAIN_DIR\)/usr/lib/swift/\$\(PLATFORM_NAME\)/ \$\(SDKROOT\)/usr/lib/swift', \s*'LD_RUNPATH_SEARCH_PATHS' => '/usr/lib/swift',[^}]* @@ -210,9 +219,11 @@ class PodspecCheckCommand extends PackageLoopingCommand { /// Returns true if [podspec] specifies a .xcprivacy file. bool _hasPrivacyManifest(File podspec) { - final RegExp manifestBundling = RegExp(r''' + final manifestBundling = RegExp( + r''' \.(?:ios\.)?resource_bundles\s*=\s*{[^}]*PrivacyInfo.xcprivacy''', - dotAll: true); + dotAll: true, + ); return manifestBundling.hasMatch(podspec.readAsStringSync()); } } diff --git a/script/tool/lib/src/publish_check_command.dart b/script/tool/lib/src/publish_check_command.dart index e2109db625af..dbb6a0711e83 100644 --- a/script/tool/lib/src/publish_check_command.dart +++ b/script/tool/lib/src/publish_check_command.dart @@ -25,20 +25,25 @@ class PublishCheckCommand extends PackageLoopingCommand { super.platform, super.gitDir, http.Client? httpClient, - }) : _pubVersionFinder = - PubVersionFinder(httpClient: httpClient ?? http.Client()) { + }) : _pubVersionFinder = PubVersionFinder( + httpClient: httpClient ?? http.Client(), + ) { argParser.addFlag( _allowPrereleaseFlag, - help: 'Allows the pre-release SDK warning to pass.\n' + help: + 'Allows the pre-release SDK warning to pass.\n' 'When enabled, a pub warning, which asks to publish the package as a pre-release version when ' 'the SDK constraint is a pre-release version, is ignored.', ); - argParser.addFlag(_machineFlag, - help: 'Switch outputs to a machine readable JSON. \n' - 'The JSON contains a "status" field indicating the final status of the command, the possible values are:\n' - ' $_statusNeedsPublish: There is at least one package need to be published. They also passed all publish checks.\n' - ' $_statusMessageNoPublish: There are no packages needs to be published. Either no pubspec change detected or all versions have already been published.\n' - ' $_statusMessageError: Some error has occurred.'); + argParser.addFlag( + _machineFlag, + help: + 'Switch outputs to a machine readable JSON. \n' + 'The JSON contains a "status" field indicating the final status of the command, the possible values are:\n' + ' $_statusNeedsPublish: There is at least one package need to be published. They also passed all publish checks.\n' + ' $_statusMessageNoPublish: There are no packages needs to be published. Either no pubspec change detected or all versions have already been published.\n' + ' $_statusMessageError: Some error has occurred.', + ); } static const String _allowPrereleaseFlag = 'allow-pre-release'; @@ -81,8 +86,9 @@ class PublishCheckCommand extends PackageLoopingCommand { // The pre-publish hook must be run first if it exists, since passing the // publish check may rely on its execution. - final bool prePublishHookPassesOrNoops = - await _validatePrePublishHook(package); + final bool prePublishHookPassesOrNoops = await _validatePrePublishHook( + package, + ); // Given that, don't run publish check if the pre-publish hook fails. _PublishCheckResult result = prePublishHookPassesOrNoops ? await _passesPublishCheck(package) @@ -91,8 +97,9 @@ class PublishCheckCommand extends PackageLoopingCommand { // But do continue with other checks to find all problems at once. if (!_passesAuthorsCheck(package)) { _printImportantStatusMessage( - 'No AUTHORS file found. Packages must include an AUTHORS file.', - isError: true); + 'No AUTHORS file found. Packages must include an AUTHORS file.', + isError: true, + ); result = _PublishCheckResult.error; } @@ -111,7 +118,7 @@ class PublishCheckCommand extends PackageLoopingCommand { @override Future handleCapturedOutput(List output) async { - final Map machineOutput = { + final machineOutput = { _statusKey: _statusStringForResult(_overallResult), _humanMessageKey: output, }; @@ -162,34 +169,28 @@ class PublishCheckCommand extends PackageLoopingCommand { workingDirectory: package.directory, ); - final StringBuffer outputBuffer = StringBuffer(); - - final Completer stdOutCompleter = Completer(); - process.stdout.listen( - (List event) { - final String output = String.fromCharCodes(event); - if (output.isNotEmpty) { - print(output); - outputBuffer.write(output); - } - }, - onDone: () => stdOutCompleter.complete(), - ); + final outputBuffer = StringBuffer(); - final Completer stdInCompleter = Completer(); - process.stderr.listen( - (List event) { - final String output = String.fromCharCodes(event); - if (output.isNotEmpty) { - // The final result is always printed on stderr, whether success or - // failure. - final bool isError = !output.contains('has 0 warnings'); - _printImportantStatusMessage(output, isError: isError); - outputBuffer.write(output); - } - }, - onDone: () => stdInCompleter.complete(), - ); + final stdOutCompleter = Completer(); + process.stdout.listen((List event) { + final output = String.fromCharCodes(event); + if (output.isNotEmpty) { + print(output); + outputBuffer.write(output); + } + }, onDone: () => stdOutCompleter.complete()); + + final stdInCompleter = Completer(); + process.stderr.listen((List event) { + final output = String.fromCharCodes(event); + if (output.isNotEmpty) { + // The final result is always printed on stderr, whether success or + // failure. + final bool isError = !output.contains('has 0 warnings'); + _printImportantStatusMessage(output, isError: isError); + outputBuffer.write(output); + } + }, onDone: () => stdInCompleter.complete()); if (await process.exitCode == 0) { return true; @@ -202,10 +203,11 @@ class PublishCheckCommand extends PackageLoopingCommand { await stdOutCompleter.future; await stdInCompleter.future; - final String output = outputBuffer.toString(); + final output = outputBuffer.toString(); return output.contains('Package has 1 warning') && output.contains( - 'Packages with an SDK constraint on a pre-release of the Dart SDK should themselves be published as a pre-release version.'); + 'Packages with an SDK constraint on a pre-release of the Dart SDK should themselves be published as a pre-release version.', + ); } /// Returns true if the package has been explicitly marked as not for @@ -218,7 +220,8 @@ class PublishCheckCommand extends PackageLoopingCommand { /// Returns the result of the publish check, or null if the package is marked /// as unpublishable. Future<_PublishCheckResult> _passesPublishCheck( - RepositoryPackage package) async { + RepositoryPackage package, + ) async { final String packageName = package.directory.basename; final Pubspec? pubspec = _tryParsePubspec(package); if (pubspec == null) { @@ -229,7 +232,9 @@ class PublishCheckCommand extends PackageLoopingCommand { final Version? version = pubspec.version; final _PublishCheckResult alreadyPublishedResult = await _checkPublishingStatus( - packageName: packageName, version: version); + packageName: packageName, + version: version, + ); if (alreadyPublishedResult == _PublishCheckResult.error) { print('Check pub version failed $packageName'); return _PublishCheckResult.error; @@ -242,7 +247,8 @@ class PublishCheckCommand extends PackageLoopingCommand { if (await _hasValidPublishCheckRun(package)) { if (alreadyPublishedResult == _PublishCheckResult.nothingToPublish) { print( - 'Package $packageName version: $version has already been published on pub.'); + 'Package $packageName version: $version has already been published on pub.', + ); } else { print('Package $packageName is able to be published.'); } @@ -254,8 +260,10 @@ class PublishCheckCommand extends PackageLoopingCommand { } // Check if `packageName` already has `version` published on pub. - Future<_PublishCheckResult> _checkPublishingStatus( - {required String packageName, required Version? version}) async { + Future<_PublishCheckResult> _checkPublishingStatus({ + required String packageName, + required Version? version, + }) async { final PubVersionFinderResponse pubVersionFinderResponse = await _pubVersionFinder.getPackageVersion(packageName: packageName); switch (pubVersionFinderResponse.result) { @@ -276,8 +284,9 @@ HTTP response: ${pubVersionFinderResponse.httpResponse.body} } bool _passesAuthorsCheck(RepositoryPackage package) { - final List pathComponents = - package.directory.fileSystem.path.split(package.path); + final List pathComponents = package.directory.fileSystem.path.split( + package.path, + ); if (pathComponents.contains('third_party')) { // Third-party packages aren't required to have an AUTHORS file. return true; @@ -291,20 +300,25 @@ HTTP response: ${pubVersionFinderResponse.httpResponse.body} // If there's no custom step, then it can't block publishing. return true; } - final String relativeScriptPath = - getRelativePosixPath(script, from: package.directory); + final String relativeScriptPath = getRelativePosixPath( + script, + from: package.directory, + ); print('Running pre-publish hook $relativeScriptPath...'); // Ensure that dependencies are available. if (!await runPubGet(package, processRunner, platform)) { - _printImportantStatusMessage('Failed to get depenedencies', - isError: true); + _printImportantStatusMessage( + 'Failed to get depenedencies', + isError: true, + ); return false; } - final int exitCode = await processRunner.runAndStream( - 'dart', ['run', relativeScriptPath], - workingDir: package.directory); + final int exitCode = await processRunner.runAndStream('dart', [ + 'run', + relativeScriptPath, + ], workingDir: package.directory); if (exitCode != 0) { _printImportantStatusMessage('Pre-publish script failed.', isError: true); return false; @@ -313,7 +327,7 @@ HTTP response: ${pubVersionFinderResponse.httpResponse.body} } void _printImportantStatusMessage(String message, {required bool isError}) { - final String statusMessage = '${isError ? 'ERROR' : 'SUCCESS'}: $message'; + final statusMessage = '${isError ? 'ERROR' : 'SUCCESS'}: $message'; if (getBoolArg(_machineFlag)) { print(statusMessage); } else { @@ -327,8 +341,4 @@ HTTP response: ${pubVersionFinderResponse.httpResponse.body} } /// Possible outcomes of of a publishing check. -enum _PublishCheckResult { - nothingToPublish, - needsPublishing, - error, -} +enum _PublishCheckResult { nothingToPublish, needsPublishing, error } diff --git a/script/tool/lib/src/publish_command.dart b/script/tool/lib/src/publish_command.dart index 8af5eb1a0f2d..4d9da43ddc40 100644 --- a/script/tool/lib/src/publish_command.dart +++ b/script/tool/lib/src/publish_command.dart @@ -55,17 +55,22 @@ class PublishCommand extends PackageLoopingCommand { io.Stdin? stdinput, super.gitDir, http.Client? httpClient, - }) : _pubVersionFinder = - PubVersionFinder(httpClient: httpClient ?? http.Client()), - _stdin = stdinput ?? io.stdin { - argParser.addFlag(_alreadyTaggedFlag, - help: - 'Instead of tagging, validates that the current checkout is already tagged with the expected version.\n' - 'This is primarily intended for use in CI publish steps triggered by tagging.', - negatable: false); - argParser.addMultiOption(_pubFlagsOption, - help: - 'A list of options that will be forwarded on to pub. Separate multiple flags with commas.'); + }) : _pubVersionFinder = PubVersionFinder( + httpClient: httpClient ?? http.Client(), + ), + _stdin = stdinput ?? io.stdin { + argParser.addFlag( + _alreadyTaggedFlag, + help: + 'Instead of tagging, validates that the current checkout is already tagged with the expected version.\n' + 'This is primarily intended for use in CI publish steps triggered by tagging.', + negatable: false, + ); + argParser.addMultiOption( + _pubFlagsOption, + help: + 'A list of options that will be forwarded on to pub. Separate multiple flags with commas.', + ); argParser.addOption( _remoteOption, help: 'The name of the remote to push the tags to.', @@ -85,14 +90,19 @@ class PublishCommand extends PackageLoopingCommand { 'This does not run `pub publish --dry-run`.\n' 'If you want to run the command with `pub publish --dry-run`, use `pub-publish-flags=--dry-run`', ); - argParser.addFlag(_skipConfirmationFlag, - help: 'Run the command without asking for Y/N inputs.\n' - 'This command will add a `--force` flag to the `pub publish` command if it is not added with $_pubFlagsOption\n'); - argParser.addFlag(_tagForAutoPublishFlag, - help: - 'Runs the dry-run publish, and tags if it succeeds, but does not actually publish.\n' - 'This is intended for use with a separate publish step that is based on tag push events.', - negatable: false); + argParser.addFlag( + _skipConfirmationFlag, + help: + 'Run the command without asking for Y/N inputs.\n' + 'This command will add a `--force` flag to the `pub publish` command if it is not added with $_pubFlagsOption\n', + ); + argParser.addFlag( + _tagForAutoPublishFlag, + help: + 'Runs the dry-run publish, and tags if it succeeds, but does not actually publish.\n' + 'This is intended for use with a separate publish step that is based on tag push events.', + negatable: false, + ); } static const String _alreadyTaggedFlag = 'already-tagged'; @@ -111,8 +121,10 @@ class PublishCommand extends PackageLoopingCommand { /// Returns the correct path where the pub credential is stored. @visibleForTesting - late final String credentialsPath = - _getCredentialsPath(platform: platform, path: path); + late final String credentialsPath = _getCredentialsPath( + platform: platform, + path: path, + ); @override final String name = 'publish'; @@ -156,8 +168,9 @@ class PublishCommand extends PackageLoopingCommand { // Pre-fetch all the repository's tags, to check against when publishing. final GitDir repository = await gitDir; - final io.ProcessResult existingTagsResult = - await repository.runCommand(['tag', '--sort=-committerdate']); + final io.ProcessResult existingTagsResult = await repository.runCommand( + ['tag', '--sort=-committerdate'], + ); _existingGitTags = (existingTagsResult.stdout as String).split('\n') ..removeWhere((String element) => element.isEmpty); @@ -175,19 +188,23 @@ class PublishCommand extends PackageLoopingCommand { Stream getPackagesToProcess() async* { if (getBoolArg(_allChangedFlag)) { print( - 'Publishing all packages that have changed relative to "$baseSha"\n'); + 'Publishing all packages that have changed relative to "$baseSha"\n', + ); final List changedPubspecs = changedFiles .where((String file) => file.trim().endsWith('pubspec.yaml')) .toList(); - for (final String pubspecPath in changedPubspecs) { + for (final pubspecPath in changedPubspecs) { // git outputs a relativa, Posix-style path. final File pubspecFile = childFileWithSubcomponents( - packagesDir.fileSystem.directory((await gitDir).path), - p.posix.split(pubspecPath)); - yield PackageEnumerationEntry(RepositoryPackage(pubspecFile.parent), - excluded: false); + packagesDir.fileSystem.directory((await gitDir).path), + p.posix.split(pubspecPath), + ); + yield PackageEnumerationEntry( + RepositoryPackage(pubspecFile.parent), + excluded: false, + ); } } else { yield* getTargetPackages(filterExcluded: false); @@ -228,7 +245,7 @@ class PublishCommand extends PackageLoopingCommand { } } - final String action = tagOnly ? 'Tagged' : 'Published'; + final action = tagOnly ? 'Tagged' : 'Published'; print('\n$action ${package.directory.basename} successfully!'); return PackageResult.success(); } @@ -264,7 +281,8 @@ Safe to ignore if the package is deleted in this commit. // TODO(cyanglaz): Make the tool also auto publish flutter_plugin_tools package. // https://github.com/flutter/flutter/issues/85430 return PackageResult.skip( - 'publishing flutter_plugin_tools via the tool is not supported'); + 'publishing flutter_plugin_tools via the tool is not supported', + ); } if (pubspec.publishTo == 'none') { @@ -273,7 +291,8 @@ Safe to ignore if the package is deleted in this commit. if (pubspec.version == null) { printError( - 'No version found. A package that intentionally has no version should be marked "publish_to: none"'); + 'No version found. A package that intentionally has no version should be marked "publish_to: none"', + ); return PackageResult.fail(['no version']); } @@ -284,15 +303,17 @@ Safe to ignore if the package is deleted in this commit. await _pubVersionFinder.getPackageVersion(packageName: pubspec.name); if (pubVersionFinderResponse.versions.contains(version)) { final String tagsForPackageWithSameVersion = _existingGitTags.firstWhere( - (String tag) => - tag.split('-v').first == pubspec.name && - tag.split('-v').last == version.toString(), - orElse: () => ''); + (String tag) => + tag.split('-v').first == pubspec.name && + tag.split('-v').last == version.toString(), + orElse: () => '', + ); if (tagsForPackageWithSameVersion.isEmpty) { printError( - '${pubspec.name} $version has already been published, however ' - 'the git release tag (${pubspec.name}-v$version) was not found. ' - 'Please manually fix the tag then run the command again.'); + '${pubspec.name} $version has already been published, however ' + 'the git release tag (${pubspec.name}-v$version) was not found. ' + 'Please manually fix the tag then run the command again.', + ); return PackageResult.fail(['published but untagged']); } else { print('${pubspec.name} $version has already been published.'); @@ -308,20 +329,17 @@ Safe to ignore if the package is deleted in this commit. Future _tagRelease(RepositoryPackage package, String tag) async { print('Tagging release $tag...'); if (!getBoolArg(_dryRunFlag)) { - final io.ProcessResult result = await (await gitDir).runCommand( - ['tag', tag], - throwOnError: false, - ); + final io.ProcessResult result = await (await gitDir).runCommand([ + 'tag', + tag, + ], throwOnError: false); if (result.exitCode != 0) { return false; } } print('Pushing tag to ${_remote.name}...'); - final bool success = await _pushTagToRemote( - tag: tag, - remote: _remote, - ); + final bool success = await _pushTagToRemote(tag: tag, remote: _remote); if (success) { print('Release tagged!'); } @@ -346,23 +364,20 @@ Safe to ignore if the package is deleted in this commit. Future _checkGitStatus(RepositoryPackage package) async { final io.ProcessResult statusResult = await (await gitDir).runCommand( - [ - 'status', - '--porcelain', - package.directory.absolute.path, - ], + ['status', '--porcelain', package.directory.absolute.path], throwOnError: false, ); if (statusResult.exitCode != 0) { return false; } - final String statusOutput = statusResult.stdout as String; + final statusOutput = statusResult.stdout as String; if (statusOutput.isNotEmpty) { printError( - "There are files in the package directory that haven't been saved in git. Refusing to publish these files:\n\n" - '$statusOutput\n' - 'If the directory should be clean, you can run `git clean -xdf && git reset --hard HEAD` to wipe all local changes.'); + "There are files in the package directory that haven't been saved in git. Refusing to publish these files:\n\n" + '$statusOutput\n' + 'If the directory should be clean, you can run `git clean -xdf && git reset --hard HEAD` to wipe all local changes.', + ); } return statusOutput.isEmpty; } @@ -383,8 +398,10 @@ Safe to ignore if the package is deleted in this commit. if (!script.existsSync()) { return true; } - final String relativeScriptPath = - getRelativePosixPath(script, from: package.directory); + final String relativeScriptPath = getRelativePosixPath( + script, + from: package.directory, + ); print('Running pre-publish hook $relativeScriptPath...'); // Ensure that dependencies are available. @@ -393,9 +410,10 @@ Safe to ignore if the package is deleted in this commit. return false; } - final int exitCode = await processRunner.runAndStream( - 'dart', ['run', relativeScriptPath], - workingDir: package.directory); + final int exitCode = await processRunner.runAndStream('dart', [ + 'run', + relativeScriptPath, + ], workingDir: package.directory); if (exitCode != 0) { printError('Pre-publish script failed.'); return false; @@ -405,8 +423,10 @@ Safe to ignore if the package is deleted in this commit. Future _publish(RepositoryPackage package) async { print('Publishing...'); - print('Running `pub publish ${_publishFlags.join(' ')}` in ' - '${package.directory.absolute.path}...\n'); + print( + 'Running `pub publish ${_publishFlags.join(' ')}` in ' + '${package.directory.absolute.path}...\n', + ); if (getBoolArg(_dryRunFlag)) { return true; } @@ -416,8 +436,10 @@ Safe to ignore if the package is deleted in this commit. } final io.Process publish = await processRunner.start( - flutterCommand, ['pub', 'publish', ..._publishFlags], - workingDirectory: package.directory); + flutterCommand, + ['pub', 'publish', ..._publishFlags], + workingDirectory: package.directory, + ); publish.stdout.transform(utf8.decoder).listen((String data) => print(data)); publish.stderr.transform(utf8.decoder).listen((String data) => print(data)); _stdinSubscription ??= _stdin @@ -435,10 +457,9 @@ Safe to ignore if the package is deleted in this commit. String _getTag(RepositoryPackage package) { final File pubspecFile = package.pubspecFile; - final YamlMap pubspecYaml = - loadYaml(pubspecFile.readAsStringSync()) as YamlMap; - final String name = pubspecYaml['name'] as String; - final String version = pubspecYaml['version'] as String; + final pubspecYaml = loadYaml(pubspecFile.readAsStringSync()) as YamlMap; + final name = pubspecYaml['name'] as String; + final version = pubspecYaml['version'] as String; // We should have failed to publish if these were unset. assert(name.isNotEmpty && version.isNotEmpty); return _tagFormat @@ -454,10 +475,11 @@ Safe to ignore if the package is deleted in this commit. required _RemoteInfo remote, }) async { if (!getBoolArg(_dryRunFlag)) { - final io.ProcessResult result = await (await gitDir).runCommand( - ['push', remote.name, tag], - throwOnError: false, - ); + final io.ProcessResult result = await (await gitDir).runCommand([ + 'push', + remote.name, + tag, + ], throwOnError: false); if (result.exitCode != 0) { return false; } @@ -487,8 +509,10 @@ If running this command on CI, you can set the pub credential content in the $_p } /// The path in which pub expects to find its credentials file. -String _getCredentialsPath( - {required Platform platform, required p.Context path}) { +String _getCredentialsPath({ + required Platform platform, + required p.Context path, +}) { // See https://github.com/dart-lang/pub/blob/master/doc/cache_layout.md#layout String? configDir; if (platform.isLinux) { diff --git a/script/tool/lib/src/pubspec_check_command.dart b/script/tool/lib/src/pubspec_check_command.dart index 397dcf81f818..77431c23094c 100644 --- a/script/tool/lib/src/pubspec_check_command.dart +++ b/script/tool/lib/src/pubspec_check_command.dart @@ -32,18 +32,24 @@ class PubspecCheckCommand extends PackageLoopingCommand { help: 'The minimum Flutter version to allow as the minimum SDK constraint.', ); - argParser.addMultiOption(_allowDependenciesFlag, - help: 'Packages (comma separated) that are allowed as dependencies or ' - 'dev_dependencies.\n\n' - 'Alternately, a list of one or more YAML files that contain a list ' - 'of allowed dependencies.', - defaultsTo: []); - argParser.addMultiOption(_allowPinnedDependenciesFlag, - help: 'Packages (comma separated) that are allowed as dependencies or ' - 'dev_dependencies only if pinned to an exact version.\n\n' - 'Alternately, a list of one or more YAML files that contain a list ' - 'of allowed pinned dependencies.', - defaultsTo: []); + argParser.addMultiOption( + _allowDependenciesFlag, + help: + 'Packages (comma separated) that are allowed as dependencies or ' + 'dev_dependencies.\n\n' + 'Alternately, a list of one or more YAML files that contain a list ' + 'of allowed dependencies.', + defaultsTo: [], + ); + argParser.addMultiOption( + _allowPinnedDependenciesFlag, + help: + 'Packages (comma separated) that are allowed as dependencies or ' + 'dev_dependencies only if pinned to an exact version.\n\n' + 'Alternately, a list of one or more YAML files that contain a list ' + 'of allowed pinned dependencies.', + defaultsTo: [], + ); } static const String _minMinFlutterVersionFlag = 'min-min-flutter-version'; @@ -104,11 +110,14 @@ class PubspecCheckCommand extends PackageLoopingCommand { @override Future initializeRun() async { // Find all local, published packages. - for (final File pubspecFile in (await packagesDir.parent - .list(recursive: true, followLinks: false) - .toList()) - .whereType() - .where((File entity) => p.basename(entity.path) == 'pubspec.yaml')) { + for (final File pubspecFile + in (await packagesDir.parent + .list(recursive: true, followLinks: false) + .toList()) + .whereType() + .where( + (File entity) => p.basename(entity.path) == 'pubspec.yaml', + )) { final Pubspec? pubspec = _tryParsePubspec(pubspecFile.readAsStringSync()); if (pubspec != null && pubspec.publishTo != 'none') { _localPackages.add(pubspec.name); @@ -142,18 +151,22 @@ class PubspecCheckCommand extends PackageLoopingCommand { final List pubspecLines = contents.split('\n'); final bool isPlugin = pubspec.flutter?.containsKey('plugin') ?? false; - final List sectionOrder = - isPlugin ? _majorPluginSections : _majorPackageSections; + final List sectionOrder = isPlugin + ? _majorPluginSections + : _majorPackageSections; bool passing = _checkSectionOrder(pubspecLines, sectionOrder); if (!passing) { - printError('${indentation}Major sections should follow standard ' - 'repository ordering:'); + printError( + '${indentation}Major sections should follow standard ' + 'repository ordering:', + ); final String listIndentation = indentation * 2; printError('$listIndentation${sectionOrder.join('\n$listIndentation')}'); } - final String minMinFlutterVersionString = - getStringArg(_minMinFlutterVersionFlag); + final String minMinFlutterVersionString = getStringArg( + _minMinFlutterVersionFlag, + ); final String? minVersionError = _checkForMinimumVersionError( pubspec, package, @@ -167,15 +180,19 @@ class PubspecCheckCommand extends PackageLoopingCommand { } if (isPlugin) { - final String? implementsError = - _checkForImplementsError(pubspec, package: package); + final String? implementsError = _checkForImplementsError( + pubspec, + package: package, + ); if (implementsError != null) { printError('$indentation$implementsError'); passing = false; } - final String? defaultPackageError = - _checkForDefaultPackageError(pubspec, package: package); + final String? defaultPackageError = _checkForDefaultPackageError( + pubspec, + package: package, + ); if (defaultPackageError != null) { printError('$indentation$defaultPackageError'); passing = false; @@ -184,20 +201,24 @@ class PubspecCheckCommand extends PackageLoopingCommand { final String? dependenciesError = _checkDependencies(pubspec); if (dependenciesError != null) { - printError(dependenciesError - .split('\n') - .map((String line) => '$indentation$line') - .join('\n')); + printError( + dependenciesError + .split('\n') + .map((String line) => '$indentation$line') + .join('\n'), + ); passing = false; } // Ignore metadata that's only relevant for published packages if the // packages is not intended for publishing. if (pubspec.publishTo != 'none') { - final List repositoryErrors = - _checkForRepositoryLinkErrors(pubspec, package: package); + final List repositoryErrors = _checkForRepositoryLinkErrors( + pubspec, + package: package, + ); if (repositoryErrors.isNotEmpty) { - for (final String error in repositoryErrors) { + for (final error in repositoryErrors) { printError('$indentation$error'); } passing = false; @@ -205,9 +226,10 @@ class PubspecCheckCommand extends PackageLoopingCommand { if (!_checkIssueLink(pubspec)) { printError( - '${indentation}A package should have an "issue_tracker" link to a ' - 'search for open flutter/flutter bugs with the relevant label:\n' - '${indentation * 2}$_expectedIssueLinkFormat'); + '${indentation}A package should have an "issue_tracker" link to a ' + 'search for open flutter/flutter bugs with the relevant label:\n' + '${indentation * 2}$_expectedIssueLinkFormat', + ); passing = false; } @@ -221,8 +243,10 @@ class PubspecCheckCommand extends PackageLoopingCommand { // the app-facing package, since they are unlisted, and are expected to // have short descriptions. if (!package.isPlatformInterface && !package.isPlatformImplementation) { - final String? descriptionError = - _checkDescription(pubspec, package: package); + final String? descriptionError = _checkDescription( + pubspec, + package: package, + ); if (descriptionError != null) { printError('$indentation$descriptionError'); passing = false; @@ -243,9 +267,11 @@ class PubspecCheckCommand extends PackageLoopingCommand { } bool _checkSectionOrder( - List pubspecLines, List sectionOrder) { - int previousSectionIndex = 0; - for (final String line in pubspecLines) { + List pubspecLines, + List sectionOrder, + ) { + var previousSectionIndex = 0; + for (final line in pubspecLines) { final int index = sectionOrder.indexOf(line); if (index == -1) { continue; @@ -262,29 +288,34 @@ class PubspecCheckCommand extends PackageLoopingCommand { Pubspec pubspec, { required RepositoryPackage package, }) { - final List errorMessages = []; + final errorMessages = []; if (pubspec.repository == null) { errorMessages.add('Missing "repository"'); } else { - final String relativePackagePath = - getRelativePosixPath(package.directory, from: packagesDir.parent); + final String relativePackagePath = getRelativePosixPath( + package.directory, + from: packagesDir.parent, + ); if (!pubspec.repository!.path.endsWith(relativePackagePath)) { - errorMessages - .add('The "repository" link should end with the package path.'); + errorMessages.add( + 'The "repository" link should end with the package path.', + ); } - if (!pubspec.repository! - .toString() - .startsWith('https://github.com/flutter/packages/tree/main')) { - errorMessages - .add('The "repository" link should start with the repository\'s ' - 'main tree: "https://github.com/flutter/packages/tree/main".'); + if (!pubspec.repository!.toString().startsWith( + 'https://github.com/flutter/packages/tree/main', + )) { + errorMessages.add( + 'The "repository" link should start with the repository\'s ' + 'main tree: "https://github.com/flutter/packages/tree/main".', + ); } } if (pubspec.homepage != null) { - errorMessages - .add('Found a "homepage" entry; only "repository" should be used.'); + errorMessages.add( + 'Found a "homepage" entry; only "repository" should be used.', + ); } return errorMessages; @@ -313,18 +344,15 @@ class PubspecCheckCommand extends PackageLoopingCommand { } bool _checkIssueLink(Pubspec pubspec) { - return pubspec.issueTracker - ?.toString() - .startsWith(_expectedIssueLinkFormat) ?? + return pubspec.issueTracker?.toString().startsWith( + _expectedIssueLinkFormat, + ) ?? false; } // Validates the "topics" keyword for a plugin, returning an error // string if there are any issues. - String? _checkTopics( - Pubspec pubspec, { - required RepositoryPackage package, - }) { + String? _checkTopics(Pubspec pubspec, {required RepositoryPackage package}) { final List topics = pubspec.topics ?? []; if (topics.isEmpty) { return 'A published package should include "topics". ' @@ -345,11 +373,13 @@ class PubspecCheckCommand extends PackageLoopingCommand { } // Validates topic names according to https://dart.dev/tools/pub/pubspec#topics - final RegExp expectedTopicFormat = RegExp(r'^[a-z](?:-?[a-z0-9]+)*$'); - final Iterable invalidTopics = topics.where((String topic) => - !expectedTopicFormat.hasMatch(topic) || - topic.length < 2 || - topic.length > 32); + final expectedTopicFormat = RegExp(r'^[a-z](?:-?[a-z0-9]+)*$'); + final Iterable invalidTopics = topics.where( + (String topic) => + !expectedTopicFormat.hasMatch(topic) || + topic.length < 2 || + topic.length > 32, + ); if (invalidTopics.isNotEmpty) { return 'Invalid topic(s): ${invalidTopics.join(', ')} in "topics" section. ' 'Topics must consist of lowercase alphanumerical characters or dash (but no double dash), ' @@ -368,8 +398,8 @@ class PubspecCheckCommand extends PackageLoopingCommand { required RepositoryPackage package, }) { if (_isImplementationPackage(package)) { - final YamlMap pluginSection = pubspec.flutter!['plugin'] as YamlMap; - final String? implements = pluginSection['implements'] as String?; + final pluginSection = pubspec.flutter!['plugin'] as YamlMap; + final implements = pluginSection['implements'] as String?; final String expectedImplements = package.directory.parent.basename; if (implements == null) { return 'Missing "implements: $expectedImplements" in "plugin" section.'; @@ -389,8 +419,8 @@ class PubspecCheckCommand extends PackageLoopingCommand { Pubspec pubspec, { required RepositoryPackage package, }) { - final YamlMap pluginSection = pubspec.flutter!['plugin'] as YamlMap; - final YamlMap? platforms = pluginSection['platforms'] as YamlMap?; + final pluginSection = pubspec.flutter!['plugin'] as YamlMap; + final platforms = pluginSection['platforms'] as YamlMap?; if (platforms == null) { logWarning('Does not implement any platforms'); return null; @@ -398,11 +428,10 @@ class PubspecCheckCommand extends PackageLoopingCommand { final String packageName = package.directory.basename; // Validate that the default_package entries look correct (e.g., no typos). - final Set defaultPackages = {}; + final defaultPackages = {}; for (final MapEntry platformEntry in platforms.entries) { - final YamlMap platformDetails = platformEntry.value! as YamlMap; - final String? defaultPackage = - platformDetails['default_package'] as String?; + final platformDetails = platformEntry.value! as YamlMap; + final defaultPackage = platformDetails['default_package'] as String?; if (defaultPackage != null) { defaultPackages.add(defaultPackage); if (!defaultPackage.startsWith('${packageName}_')) { @@ -414,8 +443,9 @@ class PubspecCheckCommand extends PackageLoopingCommand { // Validate that all default_packages are also dependencies. final Iterable dependencies = pubspec.dependencies.keys; - final Iterable missingPackages = defaultPackages - .where((String package) => !dependencies.contains(package)); + final Iterable missingPackages = defaultPackages.where( + (String package) => !dependencies.contains(package), + ); if (missingPackages.isNotEmpty) { return 'The following default_packages are missing ' 'corresponding dependencies:\n' @@ -437,7 +467,7 @@ class PubspecCheckCommand extends PackageLoopingCommand { // anything else is. (This is done instead of listing known implementation // suffixes to allow for non-standard suffixes; e.g., to put several // platforms in one package for code-sharing purposes.) - const Set nonImplementationSuffixes = { + const nonImplementationSuffixes = { '', // App-facing package. '_platform_interface', // Platform interface package. }; @@ -471,10 +501,12 @@ class PubspecCheckCommand extends PackageLoopingCommand { } } - final Version? dartConstraintMin = - _minimumForConstraint(pubspec.environment['sdk']); - final Version? flutterConstraintMin = - _minimumForConstraint(pubspec.environment['flutter']); + final Version? dartConstraintMin = _minimumForConstraint( + pubspec.environment['sdk'], + ); + final Version? flutterConstraintMin = _minimumForConstraint( + pubspec.environment['flutter'], + ); // Validate the Flutter constraint, if any. if (flutterConstraintMin != null && minMinFlutterVersion != null) { @@ -495,8 +527,9 @@ class PubspecCheckCommand extends PackageLoopingCommand { // Ensure that if there is also a Flutter constraint, they are consistent. if (flutterConstraintMin != null) { - final Version? dartVersionForFlutterMinimum = - getDartSdkForFlutterSdk(flutterConstraintMin); + final Version? dartVersionForFlutterMinimum = getDartSdkForFlutterSdk( + flutterConstraintMin, + ); if (dartVersionForFlutterMinimum == null) { return unknownDartVersionError(flutterConstraintMin); } @@ -528,13 +561,12 @@ class PubspecCheckCommand extends PackageLoopingCommand { // Validates the dependencies for a package, returning an error string if // there are any that aren't allowed. String? _checkDependencies(Pubspec pubspec) { - final Set badDependencies = {}; - final Set misplacedDevDependencies = {}; + final badDependencies = {}; + final misplacedDevDependencies = {}; // Shipped dependencies. - for (final Map dependencies - in >[ + for (final dependencies in >[ pubspec.dependencies, - pubspec.devDependencies + pubspec.devDependencies, ]) { dependencies.forEach((String name, Dependency dependency) { if (!_shouldAllowDependency(name, dependency)) { @@ -544,7 +576,7 @@ class PubspecCheckCommand extends PackageLoopingCommand { } // Ensure that dev-only dependencies aren't in `dependencies`. - const Set devOnlyDependencies = { + const devOnlyDependencies = { 'build_runner', 'integration_test', 'flutter_test', @@ -565,7 +597,7 @@ class PubspecCheckCommand extends PackageLoopingCommand { }); } - final List errors = [ + final errors = [ if (badDependencies.isNotEmpty) ''' The following unexpected non-local dependencies were found: diff --git a/script/tool/lib/src/readme_check_command.dart b/script/tool/lib/src/readme_check_command.dart index 818989d9af41..ea290d52379c 100644 --- a/script/tool/lib/src/readme_check_command.dart +++ b/script/tool/lib/src/readme_check_command.dart @@ -22,8 +22,10 @@ class ReadmeCheckCommand extends PackageLoopingCommand { super.platform, super.gitDir, }) { - argParser.addFlag(_requireExcerptsArg, - help: 'Require that Dart code blocks be managed by code-excerpt.'); + argParser.addFlag( + _requireExcerptsArg, + help: 'Require that Dart code blocks be managed by code-excerpt.', + ); } static const String _requireExcerptsArg = 'require-excerpts'; @@ -53,11 +55,19 @@ class ReadmeCheckCommand extends PackageLoopingCommand { @override Future runForPackage(RepositoryPackage package) async { - final List errors = _validateReadme(package.readmeFile, - mainPackage: package, isExample: false); + final List errors = _validateReadme( + package.readmeFile, + mainPackage: package, + isExample: false, + ); for (final RepositoryPackage packageToCheck in package.getExamples()) { - errors.addAll(_validateReadme(packageToCheck.readmeFile, - mainPackage: package, isExample: true)); + errors.addAll( + _validateReadme( + packageToCheck.readmeFile, + mainPackage: package, + isExample: true, + ), + ); } // If there's an example/README.md for a multi-example package, validate @@ -65,8 +75,13 @@ class ReadmeCheckCommand extends PackageLoopingCommand { final Directory exampleDir = package.directory.childDirectory('example'); final File exampleDirReadme = exampleDir.childFile('README.md'); if (exampleDir.existsSync() && !isPackage(exampleDir)) { - errors.addAll(_validateReadme(exampleDirReadme, - mainPackage: package, isExample: true)); + errors.addAll( + _validateReadme( + exampleDirReadme, + mainPackage: package, + isExample: true, + ), + ); } return errors.isEmpty @@ -74,40 +89,56 @@ class ReadmeCheckCommand extends PackageLoopingCommand { : PackageResult.fail(errors); } - List _validateReadme(File readme, - {required RepositoryPackage mainPackage, required bool isExample}) { + List _validateReadme( + File readme, { + required RepositoryPackage mainPackage, + required bool isExample, + }) { if (!readme.existsSync()) { if (isExample) { - print('${indentation}No README for ' - '${getRelativePosixPath(readme.parent, from: mainPackage.directory)}'); + print( + '${indentation}No README for ' + '${getRelativePosixPath(readme.parent, from: mainPackage.directory)}', + ); return []; } else { - printError('${indentation}No README found at ' - '${getRelativePosixPath(readme, from: mainPackage.directory)}'); + printError( + '${indentation}No README found at ' + '${getRelativePosixPath(readme, from: mainPackage.directory)}', + ); return ['Missing README.md']; } } - print('${indentation}Checking ' - '${getRelativePosixPath(readme, from: mainPackage.directory)}...'); + print( + '${indentation}Checking ' + '${getRelativePosixPath(readme, from: mainPackage.directory)}...', + ); final List readmeLines = readme.readAsLinesSync(); - final List errors = []; + final errors = []; - final String? blockValidationError = - _validateCodeBlocks(readmeLines, mainPackage: mainPackage); + final String? blockValidationError = _validateCodeBlocks( + readmeLines, + mainPackage: mainPackage, + ); if (blockValidationError != null) { errors.add(blockValidationError); } - errors.addAll(_validateBoilerplate(readmeLines, - mainPackage: mainPackage, isExample: isExample)); + errors.addAll( + _validateBoilerplate( + readmeLines, + mainPackage: mainPackage, + isExample: isExample, + ), + ); // Check if this is the main readme for a plugin, and if so enforce extra // checks. if (!isExample) { final Pubspec pubspec = mainPackage.parsePubspec(); - final bool isPlugin = pubspec.flutter?['plugin'] != null; + final isPlugin = pubspec.flutter?['plugin'] != null; if (isPlugin && (!mainPackage.isFederated || mainPackage.isAppFacing)) { final String? error = _validateSupportedPlatforms(readmeLines, pubspec); if (error != null) { @@ -124,14 +155,15 @@ class ReadmeCheckCommand extends PackageLoopingCommand { List readmeLines, { required RepositoryPackage mainPackage, }) { - final RegExp codeBlockDelimiterPattern = RegExp(r'^\s*```\s*([^ ]*)\s*'); - const String excerptTagStart = ' missingLanguageLines = []; - final List missingExcerptLines = []; - bool inBlock = false; - for (int i = 0; i < readmeLines.length; ++i) { - final RegExpMatch? match = - codeBlockDelimiterPattern.firstMatch(readmeLines[i]); + final codeBlockDelimiterPattern = RegExp(r'^\s*```\s*([^ ]*)\s*'); + const excerptTagStart = '[]; + final missingExcerptLines = []; + var inBlock = false; + for (var i = 0; i < readmeLines.length; ++i) { + final RegExpMatch? match = codeBlockDelimiterPattern.firstMatch( + readmeLines[i], + ); if (match == null) { continue; } @@ -161,26 +193,32 @@ class ReadmeCheckCommand extends PackageLoopingCommand { String? errorSummary; if (missingLanguageLines.isNotEmpty) { - for (final int lineNumber in missingLanguageLines) { - printError('${indentation}Code block at line $lineNumber is missing ' - 'a language identifier.'); + for (final lineNumber in missingLanguageLines) { + printError( + '${indentation}Code block at line $lineNumber is missing ' + 'a language identifier.', + ); } printError( - '\n${indentation}For each block listed above, add a language tag to ' - 'the opening block. For instance, for Dart code, use:\n' - '${indentation * 2}```dart\n'); + '\n${indentation}For each block listed above, add a language tag to ' + 'the opening block. For instance, for Dart code, use:\n' + '${indentation * 2}```dart\n', + ); errorSummary = 'Missing language identifier for code block'; } if (missingExcerptLines.isNotEmpty) { - for (final int lineNumber in missingExcerptLines) { - printError('${indentation}Dart code block at line $lineNumber is not ' - 'managed by code-excerpt.'); + for (final lineNumber in missingExcerptLines) { + printError( + '${indentation}Dart code block at line $lineNumber is not ' + 'managed by code-excerpt.', + ); } printError( - '\n${indentation}For each block listed above, add ' - 'tag on the previous line, as explained at\n' - '$_instructionUrl'); + '\n${indentation}For each block listed above, add ' + 'tag on the previous line, as explained at\n' + '$_instructionUrl', + ); errorSummary ??= 'Missing code-excerpt management for code block'; } @@ -190,13 +228,16 @@ class ReadmeCheckCommand extends PackageLoopingCommand { /// Validates that the plugin has a supported platforms table following the /// expected format, returning an error string if any issues are found. String? _validateSupportedPlatforms( - List readmeLines, Pubspec pubspec) { + List readmeLines, + Pubspec pubspec, + ) { // Example table following expected format: // | | Android | iOS | Web | // |----------------|---------|----------|------------------------| // | **Support** | SDK 21+ | iOS 10+* | [See `camera_web `][1] | - final int detailsLineNumber = readmeLines - .indexWhere((String line) => line.startsWith('| **Support**')); + final int detailsLineNumber = readmeLines.indexWhere( + (String line) => line.startsWith('| **Support**'), + ); if (detailsLineNumber == -1) { return 'No OS support table found'; } @@ -210,26 +251,29 @@ class ReadmeCheckCommand extends PackageLoopingCommand { String sortedListString(Iterable entries) { final List entryList = entries.toList(); entryList.sort( - (String a, String b) => a.toLowerCase().compareTo(b.toLowerCase())); + (String a, String b) => a.toLowerCase().compareTo(b.toLowerCase()), + ); return entryList.join(', '); } // Validate that the supported OS lists match. - final YamlMap pluginSection = pubspec.flutter!['plugin'] as YamlMap; + final pluginSection = pubspec.flutter!['plugin'] as YamlMap; final dynamic platformsEntry = pluginSection['platforms']; if (platformsEntry == null) { logWarning('Plugin not support any platforms'); return null; } - final YamlMap platformSupportMaps = platformsEntry as YamlMap; - final Set actuallySupportedPlatform = - platformSupportMaps.keys.toSet().cast(); + final platformSupportMaps = platformsEntry as YamlMap; + final Set actuallySupportedPlatform = platformSupportMaps.keys + .toSet() + .cast(); final Iterable documentedPlatforms = readmeLines[osLineNumber] .split('|') .map((String entry) => entry.trim()) .where((String entry) => entry.isNotEmpty); - final Set documentedPlatformsLowercase = - documentedPlatforms.map((String entry) => entry.toLowerCase()).toSet(); + final Set documentedPlatformsLowercase = documentedPlatforms + .map((String entry) => entry.toLowerCase()) + .toSet(); if (actuallySupportedPlatform.length != documentedPlatforms.length || actuallySupportedPlatform .intersection(documentedPlatformsLowercase) @@ -248,8 +292,9 @@ ${indentation * 2}Documented: ${sortedListString(documentedPlatformsLowercase)} .toSet() .difference(_standardPlatformNames.values.toSet()); if (incorrectCapitalizations.isNotEmpty) { - final Iterable expectedVersions = incorrectCapitalizations - .map((String name) => _standardPlatformNames[name.toLowerCase()]!); + final Iterable expectedVersions = incorrectCapitalizations.map( + (String name) => _standardPlatformNames[name.toLowerCase()]!, + ); printError(''' ${indentation}Incorrect OS capitalization: ${sortedListString(incorrectCapitalizations)} ${indentation * 2}Please use standard capitalizations: ${sortedListString(expectedVersions)} @@ -272,11 +317,13 @@ ${indentation * 2}Please use standard capitalizations: ${sortedListString(expect required RepositoryPackage mainPackage, required bool isExample, }) { - final List errors = []; + final errors = []; if (_containsTemplateFlutterBoilerplate(readmeLines)) { - printError('${indentation}The boilerplate section about getting started ' - 'with Flutter should not be left in.'); + printError( + '${indentation}The boilerplate section about getting started ' + 'with Flutter should not be left in.', + ); errors.add('Contains template boilerplate'); } @@ -285,15 +332,19 @@ ${indentation * 2}Please use standard capitalizations: ${sortedListString(expect // confusion for plugin clients who find them. if (isExample && mainPackage.isPlatformImplementation) { if (_containsExampleBoilerplate(readmeLines)) { - printError('${indentation}The boilerplate should not be left in for a ' - "federated plugin implementation package's example."); + printError( + '${indentation}The boilerplate should not be left in for a ' + "federated plugin implementation package's example.", + ); errors.add('Contains template boilerplate'); } if (!_containsImplementationExampleExplanation(readmeLines)) { - printError('${indentation}The example README for a platform ' - 'implementation package should warn readers about its intended ' - 'use. Please copy the example README from another implementation ' - 'package in this repository.'); + printError( + '${indentation}The example README for a platform ' + 'implementation package should warn readers about its intended ' + 'use. Please copy the example README from another implementation ' + 'package in this repository.', + ); errors.add('Missing implementation package example warning'); } } @@ -304,15 +355,17 @@ ${indentation * 2}Please use standard capitalizations: ${sortedListString(expect /// Returns true if the README still has unwanted parts of the boilerplate /// from the `flutter create` templates. bool _containsTemplateFlutterBoilerplate(List readmeLines) { - return readmeLines.any((String line) => - line.contains('For help getting started with Flutter')); + return readmeLines.any( + (String line) => line.contains('For help getting started with Flutter'), + ); } /// Returns true if the README still has the generic description of an /// example from the `flutter create` templates. bool _containsExampleBoilerplate(List readmeLines) { - return readmeLines - .any((String line) => line.contains('Demonstrates how to use the')); + return readmeLines.any( + (String line) => line.contains('Demonstrates how to use the'), + ); } /// Returns true if the README contains the repository-standard explanation of @@ -320,9 +373,11 @@ ${indentation * 2}Please use standard capitalizations: ${sortedListString(expect bool _containsImplementationExampleExplanation(List readmeLines) { return (readmeLines.contains('# Platform Implementation Test App') && readmeLines.any( - (String line) => line.contains('This is a test app for'))) || + (String line) => line.contains('This is a test app for'), + )) || (readmeLines.contains('# Platform Implementation Test Apps') && readmeLines.any( - (String line) => line.contains('These are test apps for'))); + (String line) => line.contains('These are test apps for'), + )); } } diff --git a/script/tool/lib/src/remove_dev_dependencies_command.dart b/script/tool/lib/src/remove_dev_dependencies_command.dart index 441fa25e6596..21c7ed5b2274 100644 --- a/script/tool/lib/src/remove_dev_dependencies_command.dart +++ b/script/tool/lib/src/remove_dev_dependencies_command.dart @@ -15,16 +15,14 @@ import 'common/repository_package.dart'; /// clients of the library, but not for development of the library. class RemoveDevDependenciesCommand extends PackageLoopingCommand { /// Creates a publish metadata updater command instance. - RemoveDevDependenciesCommand( - super.packagesDir, { - super.gitDir, - }); + RemoveDevDependenciesCommand(super.packagesDir, {super.gitDir}); @override final String name = 'remove-dev-dependencies'; @override - final String description = 'Removes any dev_dependencies section from a ' + final String description = + 'Removes any dev_dependencies section from a ' 'package, to allow more legacy testing.'; @override @@ -36,13 +34,11 @@ class RemoveDevDependenciesCommand extends PackageLoopingCommand { @override Future runForPackage(RepositoryPackage package) async { - bool changed = false; - final YamlEditor editablePubspec = - YamlEditor(package.pubspecFile.readAsStringSync()); - const String devDependenciesKey = 'dev_dependencies'; + var changed = false; + final editablePubspec = YamlEditor(package.pubspecFile.readAsStringSync()); + const devDependenciesKey = 'dev_dependencies'; final YamlNode root = editablePubspec.parseAt([]); - final YamlMap? devDependencies = - (root as YamlMap)[devDependenciesKey] as YamlMap?; + final devDependencies = (root as YamlMap)[devDependenciesKey] as YamlMap?; if (devDependencies != null) { changed = true; print('${indentation}Removed dev_dependencies'); diff --git a/script/tool/lib/src/repo_package_info_check_command.dart b/script/tool/lib/src/repo_package_info_check_command.dart index c8d50eef9e15..81876092e5a2 100644 --- a/script/tool/lib/src/repo_package_info_check_command.dart +++ b/script/tool/lib/src/repo_package_info_check_command.dart @@ -15,7 +15,7 @@ const int _exitUnknownPackageEntry = 4; const Map _validCiConfigSyntax = { 'release': { - 'batch': {true, false} + 'batch': {true, false}, }, }; @@ -55,7 +55,7 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand { _repoRoot = packagesDir.fileSystem.directory((await gitDir).path); // Extract all of the README.md table entries. - final RegExp namePattern = RegExp(r'\[(.*?)\]\('); + final namePattern = RegExp(r'\[(.*?)\]\('); for (final String line in _repoRoot.childFile('README.md').readAsLinesSync()) { // Find all the table entries, skipping the header. @@ -68,8 +68,10 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand { .where((String s) => s.isNotEmpty) .toList(); // Extract the name, removing any markdown escaping. - final String? name = - namePattern.firstMatch(cells[0])?.group(1)?.replaceAll(r'\_', '_'); + final String? name = namePattern + .firstMatch(cells[0]) + ?.group(1) + ?.replaceAll(r'\_', '_'); if (name == null) { printError('Unexpected README table line:\n $line'); throw ToolExit(_exitBadTableEntry); @@ -85,8 +87,9 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand { } // Extract all of the CODEOWNERS package entries. - final RegExp packageOwnershipPattern = - RegExp(r'^((?:third_party/)?packages/(?:[^/]*/)?([^/]*))/\*\*'); + final packageOwnershipPattern = RegExp( + r'^((?:third_party/)?packages/(?:[^/]*/)?([^/]*))/\*\*', + ); for (final String line in _repoRoot.childFile('CODEOWNERS').readAsLinesSync()) { final RegExpMatch? match = packageOwnershipPattern.firstMatch(line); @@ -105,12 +108,14 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand { // Extract all of the lebeler.yml package entries. // Validate the match rules rather than the label itself, as the labels // don't always correspond 1:1 to packages and package names. - final RegExp packageGlobPattern = - RegExp(r'^\s*-\s*(?:third_party/)?packages/([^*]*)/'); - for (final String line in _repoRoot - .childDirectory('.github') - .childFile('labeler.yml') - .readAsLinesSync()) { + final packageGlobPattern = RegExp( + r'^\s*-\s*(?:third_party/)?packages/([^*]*)/', + ); + for (final String line + in _repoRoot + .childDirectory('.github') + .childFile('labeler.yml') + .readAsLinesSync()) { final RegExpMatch? match = packageGlobPattern.firstMatch(line); if (match == null) { continue; @@ -123,7 +128,7 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand { @override Future runForPackage(RepositoryPackage package) async { final String packageName = package.directory.basename; - final List errors = []; + final errors = []; // All packages should have an owner. // Platform interface packages are considered to be owned by the app-facing @@ -146,7 +151,8 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand { // The content of ci_config.yaml must be valid if there is one. if (package.ciConfigFile.existsSync()) { errors.addAll( - _validateCiConfig(package.ciConfigFile, mainPackage: package)); + _validateCiConfig(package.ciConfigFile, mainPackage: package), + ); } // All published packages should have a README.md entry. @@ -160,7 +166,7 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand { } List _validateRootReadme(RepositoryPackage package) { - final List errors = []; + final errors = []; // For federated plugins, only the app-facing package is listed. if (package.isFederated && !package.isAppFacing) { @@ -174,19 +180,22 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand { errors.add('Missing repo root README.md table entry'); } else { // Extract the two parts of a "[label](link)" .md link. - final RegExp mdLinkPattern = RegExp(r'^\[(.*)\]\((.*)\)$'); + final mdLinkPattern = RegExp(r'^\[(.*)\]\((.*)\)$'); // Possible link targets. for (final String cell in cells) { final RegExpMatch? match = mdLinkPattern.firstMatch(cell); if (match == null) { printError( - '${indentation}Invalid repo root README.md table entry: "$cell"'); + '${indentation}Invalid repo root README.md table entry: "$cell"', + ); errors.add('Invalid root README.md table entry'); } else { - final String encodedIssueTag = - Uri.encodeComponent(_issueTagForPackage(packageName)); - final String encodedPRTag = - Uri.encodeComponent(_prTagForPackage(packageName)); + final String encodedIssueTag = Uri.encodeComponent( + _issueTagForPackage(packageName), + ); + final String encodedPRTag = Uri.encodeComponent( + _prTagForPackage(packageName), + ); final String anchor = match.group(1)!; final String target = match.group(2)!; @@ -194,25 +203,29 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand { // - The package name (optionally with any underscores escaped) // - An image with a name-based link // - An image with a tag-based link - final RegExp packageLink = - RegExp(r'^!\[.*\]\(https://img.shields.io/pub/.*/' - '$packageName' - r'(?:\.svg)?\)$'); - final RegExp issueTagLink = RegExp( - r'^!\[.*\]\(https://img.shields.io/github/issues/flutter/flutter/' - '$encodedIssueTag' - r'\?label=\)$'); - final RegExp prTagLink = RegExp( - r'^!\[.*\]\(https://img.shields.io/github/issues-pr/flutter/packages/' - '$encodedPRTag' - r'\?label=\)$'); + final packageLink = RegExp( + r'^!\[.*\]\(https://img.shields.io/pub/.*/' + '$packageName' + r'(?:\.svg)?\)$', + ); + final issueTagLink = RegExp( + r'^!\[.*\]\(https://img.shields.io/github/issues/flutter/flutter/' + '$encodedIssueTag' + r'\?label=\)$', + ); + final prTagLink = RegExp( + r'^!\[.*\]\(https://img.shields.io/github/issues-pr/flutter/packages/' + '$encodedPRTag' + r'\?label=\)$', + ); if (!(anchor == packageName || anchor == packageName.replaceAll('_', r'\_') || packageLink.hasMatch(anchor) || issueTagLink.hasMatch(anchor) || prTagLink.hasMatch(anchor))) { printError( - '${indentation}Incorrect anchor in root README.md table: "$anchor"'); + '${indentation}Incorrect anchor in root README.md table: "$anchor"', + ); errors.add('Incorrect anchor in root README.md table'); } @@ -220,19 +233,23 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand { // - a relative link to the in-repo package // - a pub.dev link to the package // - a github label link to the package's label - final RegExp pubDevLink = - RegExp('^https://pub.dev/packages/$packageName(?:/score)?\$'); - final RegExp gitHubIssueLink = RegExp( - '^https://github.com/flutter/flutter/labels/$encodedIssueTag\$'); - final RegExp gitHubPRLink = RegExp( - '^https://github.com/flutter/packages/labels/$encodedPRTag\$'); + final pubDevLink = RegExp( + '^https://pub.dev/packages/$packageName(?:/score)?\$', + ); + final gitHubIssueLink = RegExp( + '^https://github.com/flutter/flutter/labels/$encodedIssueTag\$', + ); + final gitHubPRLink = RegExp( + '^https://github.com/flutter/packages/labels/$encodedPRTag\$', + ); if (!(target == './packages/$packageName/' || target == './third_party/packages/$packageName/' || pubDevLink.hasMatch(target) || gitHubIssueLink.hasMatch(target) || gitHubPRLink.hasMatch(target))) { printError( - '${indentation}Incorrect link in root README.md table: "$target"'); + '${indentation}Incorrect link in root README.md table: "$target"', + ); errors.add('Incorrect link in root README.md table'); } } @@ -241,10 +258,14 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand { return errors; } - List _validateCiConfig(File ciConfig, - {required RepositoryPackage mainPackage}) { - print('${indentation}Checking ' - '${getRelativePosixPath(ciConfig, from: mainPackage.directory)}...'); + List _validateCiConfig( + File ciConfig, { + required RepositoryPackage mainPackage, + }) { + print( + '${indentation}Checking ' + '${getRelativePosixPath(ciConfig, from: mainPackage.directory)}...', + ); final YamlMap config; try { final Object? yaml = loadYaml(ciConfig.readAsStringSync()); @@ -255,7 +276,8 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand { config = yaml; } on YamlException catch (e) { printError( - '${indentation}Invalid YAML in ${getRelativePosixPath(ciConfig, from: mainPackage.directory)}:'); + '${indentation}Invalid YAML in ${getRelativePosixPath(ciConfig, from: mainPackage.directory)}:', + ); printError(e.toString()); return ['Invalid YAML']; } @@ -263,15 +285,20 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand { return _checkCiConfigEntries(config, syntax: _validCiConfigSyntax); } - List _checkCiConfigEntries(YamlMap config, - {required Map syntax, String configPrefix = ''}) { - final List errors = []; + List _checkCiConfigEntries( + YamlMap config, { + required Map syntax, + String configPrefix = '', + }) { + final errors = []; for (final MapEntry entry in config.entries) { if (!syntax.containsKey(entry.key)) { printError( - '${indentation}Unknown key `${entry.key}` in config${_formatConfigPrefix(configPrefix)}, the possible keys are ${syntax.keys.toList()}'); + '${indentation}Unknown key `${entry.key}` in config${_formatConfigPrefix(configPrefix)}, the possible keys are ${syntax.keys.toList()}', + ); errors.add( - 'Unknown key `${entry.key}` in config${_formatConfigPrefix(configPrefix)}'); + 'Unknown key `${entry.key}` in config${_formatConfigPrefix(configPrefix)}', + ); } else { final Object syntaxValue = syntax[entry.key]!; configPrefix = configPrefix.isEmpty @@ -280,19 +307,27 @@ class RepoPackageInfoCheckCommand extends PackageLoopingCommand { if (syntaxValue is Set) { if (!syntaxValue.contains(entry.value)) { printError( - '${indentation}Invalid value `${entry.value}` for key${_formatConfigPrefix(configPrefix)}, the possible values are ${syntaxValue.toList()}'); + '${indentation}Invalid value `${entry.value}` for key${_formatConfigPrefix(configPrefix)}, the possible values are ${syntaxValue.toList()}', + ); errors.add( - 'Invalid value `${entry.value}` for key${_formatConfigPrefix(configPrefix)}'); + 'Invalid value `${entry.value}` for key${_formatConfigPrefix(configPrefix)}', + ); } } else if (entry.value is! YamlMap) { printError( - '${indentation}Invalid value `${entry.value}` for key${_formatConfigPrefix(configPrefix)}, the value must be a map'); + '${indentation}Invalid value `${entry.value}` for key${_formatConfigPrefix(configPrefix)}, the value must be a map', + ); errors.add( - 'Invalid value `${entry.value}` for key${_formatConfigPrefix(configPrefix)}'); + 'Invalid value `${entry.value}` for key${_formatConfigPrefix(configPrefix)}', + ); } else { - errors.addAll(_checkCiConfigEntries(entry.value! as YamlMap, + errors.addAll( + _checkCiConfigEntries( + entry.value! as YamlMap, syntax: syntaxValue as Map, - configPrefix: configPrefix)); + configPrefix: configPrefix, + ), + ); } } } diff --git a/script/tool/lib/src/update_dependency_command.dart b/script/tool/lib/src/update_dependency_command.dart index 33adb389fcf0..8f2e5bfcaf06 100644 --- a/script/tool/lib/src/update_dependency_command.dart +++ b/script/tool/lib/src/update_dependency_command.dart @@ -34,36 +34,37 @@ class UpdateDependencyCommand extends PackageLoopingCommand { super.processRunner, super.gitDir, http.Client? httpClient, - }) : _pubVersionFinder = - PubVersionFinder(httpClient: httpClient ?? http.Client()) { + }) : _pubVersionFinder = PubVersionFinder( + httpClient: httpClient ?? http.Client(), + ) { + argParser.addOption(_pubPackageFlag, help: 'A pub package to update.'); argParser.addOption( - _pubPackageFlag, - help: 'A pub package to update.', + _androidDependency, + help: 'An Android dependency to update.', + allowed: [ + _AndroidDependencyType.gradle, + _AndroidDependencyType.androidGradlePlugin, + _AndroidDependencyType.kotlinGradlePlugin, + _AndroidDependencyType.compileSdk, + _AndroidDependencyType.compileSdkForExamples, + ], + allowedHelp: { + _AndroidDependencyType.gradle: + 'Updates Gradle version used in plugin example apps.', + _AndroidDependencyType.androidGradlePlugin: + 'Updates AGP version used in plugin example apps.', + _AndroidDependencyType.kotlinGradlePlugin: + 'Updates KGP version used in plugin example apps.', + _AndroidDependencyType.compileSdk: + 'Updates compileSdk version used to compile plugins.', + _AndroidDependencyType.compileSdkForExamples: + 'Updates compileSdk version used to compile plugin examples.', + }, ); - argParser.addOption(_androidDependency, - help: 'An Android dependency to update.', - allowed: [ - _AndroidDependencyType.gradle, - _AndroidDependencyType.androidGradlePlugin, - _AndroidDependencyType.kotlinGradlePlugin, - _AndroidDependencyType.compileSdk, - _AndroidDependencyType.compileSdkForExamples, - ], - allowedHelp: { - _AndroidDependencyType.gradle: - 'Updates Gradle version used in plugin example apps.', - _AndroidDependencyType.androidGradlePlugin: - 'Updates AGP version used in plugin example apps.', - _AndroidDependencyType.kotlinGradlePlugin: - 'Updates KGP version used in plugin example apps.', - _AndroidDependencyType.compileSdk: - 'Updates compileSdk version used to compile plugins.', - _AndroidDependencyType.compileSdkForExamples: - 'Updates compileSdk version used to compile plugin examples.', - }); argParser.addOption( _versionFlag, - help: 'The version to update to.\n\n' + help: + 'The version to update to.\n\n' '- For pub, defaults to the latest published version if not ' 'provided. This can be any constraint that pubspec.yaml allows; a ' 'specific version will be treated as the exact version for ' @@ -98,15 +99,14 @@ class UpdateDependencyCommand extends PackageLoopingCommand { @override Future initializeRun() async { - const Set targetFlags = { - _pubPackageFlag, - _androidDependency - }; - final Set passedTargetFlags = - targetFlags.where((String flag) => argResults![flag] != null).toSet(); + const targetFlags = {_pubPackageFlag, _androidDependency}; + final Set passedTargetFlags = targetFlags + .where((String flag) => argResults![flag] != null) + .toSet(); if (passedTargetFlags.length != 1) { printError( - 'Exactly one of the target flags must be provided: (${targetFlags.join(', ')})'); + 'Exactly one of the target flags must be provided: (${targetFlags.join(', ')})', + ); throw ToolExit(_exitIncorrectTargetDependency); } @@ -116,7 +116,7 @@ class UpdateDependencyCommand extends PackageLoopingCommand { final String? version = getNullableStringArg(_versionFlag); if (version == null) { final PubVersionFinderResponse response = await _pubVersionFinder - .getPackageVersion(packageName: _targetPubPackage!); + .getPackageVersion(packageName: _targetPubPackage); switch (response.result) { case PubVersionFinderResult.success: _targetVersion = response.versions.first.toString(); @@ -146,9 +146,10 @@ ${response.httpResponse.body} } else if (_targetAndroidDependency == _AndroidDependencyType.gradle || _targetAndroidDependency == _AndroidDependencyType.androidGradlePlugin) { - final RegExp validGradleAGPVersionPattern = - RegExp(r'^\d{1,2}\.\d{1,2}(?:\.\d)?$'); - final bool isValidGradleAGPVersion = + final validGradleAGPVersionPattern = RegExp( + r'^\d{1,2}\.\d{1,2}(?:\.\d)?$', + ); + final isValidGradleAGPVersion = validGradleAGPVersionPattern.stringMatch(version) == version; if (!isValidGradleAGPVersion) { printError(''' @@ -160,8 +161,8 @@ A version with a valid format (maximum 2-3 numbers separated by 1-2 periods) mus } } else if (_targetAndroidDependency == _AndroidDependencyType.kotlinGradlePlugin) { - final RegExp validKgpVersionPattern = RegExp(r'^\d\.\d\.\d{1,2}$'); - final bool isValidKgpVersion = + final validKgpVersionPattern = RegExp(r'^\d\.\d\.\d{1,2}$'); + final isValidKgpVersion = validKgpVersionPattern.stringMatch(version) == version; if (!isValidKgpVersion) { printError(''' @@ -175,18 +176,20 @@ A version with a valid format (3 numbers separated by 2 periods) must be provide _AndroidDependencyType.compileSdk || _targetAndroidDependency == _AndroidDependencyType.compileSdkForExamples) { - final RegExp validSdkVersion = RegExp(r'^\d{1,2}$'); - final bool isValidSdkVersion = + final validSdkVersion = RegExp(r'^\d{1,2}$'); + final isValidSdkVersion = validSdkVersion.stringMatch(version) == version; if (!isValidSdkVersion) { printError( - 'A valid Android SDK version number (1-2 digit numbers) must be provided.'); + 'A valid Android SDK version number (1-2 digit numbers) must be provided.', + ); throw ToolExit(_exitInvalidTargetVersion); } } else { // TODO(camsim99): Add other supported Android dependencies like the min/target Android SDK and AGP. printError( - 'Target Android dependency $_targetAndroidDependency is unrecognized.'); + 'Target Android dependency $_targetAndroidDependency is unrecognized.', + ); throw ToolExit(_exitIncorrectTargetDependency); } _targetVersion = version; @@ -201,7 +204,7 @@ A version with a valid format (3 numbers separated by 2 periods) must be provide @override Future runForPackage(RepositoryPackage package) async { if (_targetPubPackage != null) { - return _runForPubDependency(package, _targetPubPackage!); + return _runForPubDependency(package, _targetPubPackage); } if (_targetAndroidDependency != null) { return _runForAndroidDependency(package); @@ -215,9 +218,13 @@ A version with a valid format (3 numbers separated by 2 periods) must be provide /// Handles all of the updates for [package] when the target dependency is /// a pub dependency. Future _runForPubDependency( - RepositoryPackage package, String dependency) async { - final _PubDependencyInfo? dependencyInfo = - _getPubDependencyInfo(package, dependency); + RepositoryPackage package, + String dependency, + ) async { + final _PubDependencyInfo? dependencyInfo = _getPubDependencyInfo( + package, + dependency, + ); if (dependencyInfo == null) { return PackageResult.skip('Does not depend on $dependency'); } else if (!dependencyInfo.hosted) { @@ -225,12 +232,11 @@ A version with a valid format (3 numbers separated by 2 periods) must be provide } // Determine the target version constraint. - final String sectionKey = dependencyInfo.type == _PubDependencyType.dev + final sectionKey = dependencyInfo.type == _PubDependencyType.dev ? 'dev_dependencies' : 'dependencies'; final String versionString; - final VersionConstraint parsedConstraint = - VersionConstraint.parse(_targetVersion); + final parsedConstraint = VersionConstraint.parse(_targetVersion); // If the provided string was a constraint, or if it's a specific // version but the package has a pinned dependency, use it as-is. if (dependencyInfo.pinned || @@ -248,12 +254,8 @@ A version with a valid format (3 numbers separated by 2 periods) must be provide if (versionString == dependencyInfo.constraintString) { return PackageResult.skip('Already depends on $versionString'); } - final YamlEditor editablePubspec = - YamlEditor(package.pubspecFile.readAsStringSync()); - editablePubspec.update( - [sectionKey, dependency], - versionString, - ); + final editablePubspec = YamlEditor(package.pubspecFile.readAsStringSync()); + editablePubspec.update([sectionKey, dependency], versionString); package.pubspecFile.writeAsStringSync(editablePubspec.toString()); // Do any dependency-specific extra processing. @@ -275,7 +277,8 @@ A version with a valid format (3 numbers separated by 2 periods) must be provide /// Handles all of the updates for [package] when the target dependency is /// an Android dependency. Future _runForAndroidDependency( - RepositoryPackage package) async { + RepositoryPackage package, + ) async { if (_targetAndroidDependency == _AndroidDependencyType.compileSdk) { return _runForCompileSdkVersion(package); } else if (_targetAndroidDependency == _AndroidDependencyType.gradle || @@ -288,23 +291,25 @@ A version with a valid format (3 numbers separated by 2 periods) must be provide } return PackageResult.fail([ - 'Target Android dependency $_androidDependency is unrecognized.' + 'Target Android dependency $_androidDependency is unrecognized.', ]); } Future _runForAndroidDependencyOnExamples( - RepositoryPackage package) async { + RepositoryPackage package, + ) async { final Iterable packageExamples = package.getExamples(); - bool updateRanForExamples = false; - for (final RepositoryPackage example in packageExamples) { + var updateRanForExamples = false; + for (final example in packageExamples) { if (!example.platformDirectory(FlutterPlatform.android).existsSync()) { continue; } updateRanForExamples = true; - final Directory androidDirectory = - example.platformDirectory(FlutterPlatform.android); - final List filesToUpdate = []; + final Directory androidDirectory = example.platformDirectory( + FlutterPlatform.android, + ); + final filesToUpdate = []; final RegExp dependencyVersionPattern; final String newDependencyVersionEntry; @@ -313,24 +318,30 @@ A version with a valid format (3 numbers separated by 2 periods) must be provide .childDirectory('gradle') .childDirectory('wrapper') .existsSync()) { - filesToUpdate.add(androidDirectory - .childDirectory('gradle') - .childDirectory('wrapper') - .childFile('gradle-wrapper.properties')); + filesToUpdate.add( + androidDirectory + .childDirectory('gradle') + .childDirectory('wrapper') + .childFile('gradle-wrapper.properties'), + ); } if (androidDirectory .childDirectory('app') .childDirectory('gradle') .childDirectory('wrapper') .existsSync()) { - filesToUpdate.add(androidDirectory - .childDirectory('app') - .childDirectory('gradle') - .childDirectory('wrapper') - .childFile('gradle-wrapper.properties')); + filesToUpdate.add( + androidDirectory + .childDirectory('app') + .childDirectory('gradle') + .childDirectory('wrapper') + .childFile('gradle-wrapper.properties'), + ); } - dependencyVersionPattern = - RegExp(r'^\s*distributionUrl\s*=\s*.*\.zip', multiLine: true); + dependencyVersionPattern = RegExp( + r'^\s*distributionUrl\s*=\s*.*\.zip', + multiLine: true, + ); // TODO(camsim99): Validate current AGP version against target Gradle // version: https://github.com/flutter/flutter/issues/133887. newDependencyVersionEntry = @@ -338,9 +349,11 @@ A version with a valid format (3 numbers separated by 2 periods) must be provide } else if (_targetAndroidDependency == _AndroidDependencyType.compileSdkForExamples) { filesToUpdate.add( - androidDirectory.childDirectory('app').childFile('build.gradle')); + androidDirectory.childDirectory('app').childFile('build.gradle'), + ); dependencyVersionPattern = RegExp( - r'(compileSdk|compileSdkVersion) (\d{1,2}|flutter.compileSdkVersion)'); + r'(compileSdk|compileSdkVersion) (\d{1,2}|flutter.compileSdkVersion)', + ); newDependencyVersionEntry = 'compileSdk $_targetVersion'; } else if (_targetAndroidDependency == _AndroidDependencyType.androidGradlePlugin) { @@ -348,8 +361,9 @@ A version with a valid format (3 numbers separated by 2 periods) must be provide filesToUpdate.add(androidDirectory.childFile('settings.gradle')); } dependencyVersionPattern = RegExp( - r'^\s*id\s+"com\.android\.application"\s+version\s+"(\d{1,2}\.\d{1,2}(?:\.\d)?)"\s+apply\s+false\s*$', - multiLine: true); + r'^\s*id\s+"com\.android\.application"\s+version\s+"(\d{1,2}\.\d{1,2}(?:\.\d)?)"\s+apply\s+false\s*$', + multiLine: true, + ); newDependencyVersionEntry = 'id "com.android.application" version "$_targetVersion" apply false'; } else if (_targetAndroidDependency == @@ -358,30 +372,35 @@ A version with a valid format (3 numbers separated by 2 periods) must be provide filesToUpdate.add(androidDirectory.childFile('settings.gradle')); } dependencyVersionPattern = RegExp( - r'^\s*id\s+"org\.jetbrains\.kotlin\.android"\s+version\s+"(\d\.\d\.\d{1,2})"\s+apply\s+false\s*$', - multiLine: true); + r'^\s*id\s+"org\.jetbrains\.kotlin\.android"\s+version\s+"(\d\.\d\.\d{1,2})"\s+apply\s+false\s*$', + multiLine: true, + ); newDependencyVersionEntry = ' id "org.jetbrains.kotlin.android" version "$_targetVersion" apply false'; } else { printError( - 'Target Android dependency $_targetAndroidDependency is unrecognized.'); + 'Target Android dependency $_targetAndroidDependency is unrecognized.', + ); throw ToolExit(_exitIncorrectTargetDependency); } - for (final File fileToUpdate in filesToUpdate) { + for (final fileToUpdate in filesToUpdate) { final String oldFileToUpdateContents = fileToUpdate.readAsStringSync(); if (!dependencyVersionPattern.hasMatch(oldFileToUpdateContents)) { return PackageResult.fail([ - 'Unable to find a $_targetAndroidDependency version entry to update for ${example.displayName}.' + 'Unable to find a $_targetAndroidDependency version entry to update for ${example.displayName}.', ]); } print( - '${indentation}Updating ${getRelativePosixPath(example.directory, from: package.directory)} to "$_targetVersion"'); + '${indentation}Updating ${getRelativePosixPath(example.directory, from: package.directory)} to "$_targetVersion"', + ); final String newGradleWrapperPropertiesContents = oldFileToUpdateContents.replaceFirst( - dependencyVersionPattern, newDependencyVersionEntry); + dependencyVersionPattern, + newDependencyVersionEntry, + ); fileToUpdate.writeAsStringSync(newGradleWrapperPropertiesContents); } @@ -392,26 +411,30 @@ A version with a valid format (3 numbers separated by 2 periods) must be provide } Future _runForCompileSdkVersion( - RepositoryPackage package) async { + RepositoryPackage package, + ) async { if (!package.platformDirectory(FlutterPlatform.android).existsSync()) { return PackageResult.skip( - 'Package ${package.displayName} does not run on Android.'); + 'Package ${package.displayName} does not run on Android.', + ); } else if (package.isExample) { // We skip examples for this command. return PackageResult.skip( - 'Package ${package.displayName} is not a top-level package; run with "compileSdkForExamples" to update.'); + 'Package ${package.displayName} is not a top-level package; run with "compileSdkForExamples" to update.', + ); } final File buildConfigurationFile = package .platformDirectory(FlutterPlatform.android) .childFile('build.gradle'); - final String buildConfigurationContents = - buildConfigurationFile.readAsStringSync(); - final RegExp validCompileSdkVersion = - RegExp(r'(compileSdk|compileSdkVersion) \d{1,2}'); + final String buildConfigurationContents = buildConfigurationFile + .readAsStringSync(); + final validCompileSdkVersion = RegExp( + r'(compileSdk|compileSdkVersion) \d{1,2}', + ); if (!validCompileSdkVersion.hasMatch(buildConfigurationContents)) { return PackageResult.fail([ - 'Unable to find a compileSdk version entry to update for ${package.displayName}.' + 'Unable to find a compileSdk version entry to update for ${package.displayName}.', ]); } print('${indentation}Updating ${package.directory} to "$_targetVersion"'); @@ -425,7 +448,9 @@ A version with a valid format (3 numbers separated by 2 periods) must be provide /// Returns information about the current dependency of [package] on /// the package named [dependencyName], or null if there is no dependency. _PubDependencyInfo? _getPubDependencyInfo( - RepositoryPackage package, String dependencyName) { + RepositoryPackage package, + String dependencyName, + ) { final Pubspec pubspec = package.parsePubspec(); Dependency? dependency; @@ -460,10 +485,9 @@ A version with a valid format (3 numbers separated by 2 periods) must be provide if (!pigeonsDir.existsSync()) { return []; } - return pigeonsDir - .listSync() - .whereType() - .where((File file) => file.basename.endsWith('.dart')); + return pigeonsDir.listSync().whereType().where( + (File file) => file.basename.endsWith('.dart'), + ); } /// Re-runs Pigeon generation for [package]. @@ -480,22 +504,32 @@ A version with a valid format (3 numbers separated by 2 periods) must be provide } print('${indentation}Running pub get...'); - if (!await runPubGet(package, processRunner, platform, - streamOutput: false)) { + if (!await runPubGet( + package, + processRunner, + platform, + streamOutput: false, + )) { printError('${indentation}Fetching dependencies failed'); return false; } print('${indentation}Updating Pigeon files...'); - for (final File input in inputs) { - final String relativePath = - getRelativePosixPath(input, from: package.directory); + for (final input in inputs) { + final String relativePath = getRelativePosixPath( + input, + from: package.directory, + ); final io.ProcessResult pigeonResult = await processRunner.run( - 'dart', ['run', 'pigeon', '--input', relativePath], - workingDir: package.directory); + 'dart', + ['run', 'pigeon', '--input', relativePath], + workingDir: package.directory, + ); if (pigeonResult.exitCode != 0) { - printError('dart run pigeon failed (${pigeonResult.exitCode}):\n' - '${pigeonResult.stdout}\n${pigeonResult.stderr}\n'); + printError( + 'dart run pigeon failed (${pigeonResult.exitCode}):\n' + '${pigeonResult.stdout}\n${pigeonResult.stderr}\n', + ); return false; } } @@ -507,31 +541,33 @@ A version with a valid format (3 numbers separated by 2 periods) must be provide final Pubspec pubspec = package.parsePubspec(); if (!pubspec.devDependencies.keys.contains('build_runner')) { print( - '${indentation}No build_runner dependency; skipping mock regeneration.'); + '${indentation}No build_runner dependency; skipping mock regeneration.', + ); return true; } print('${indentation}Running pub get...'); - if (!await runPubGet(package, processRunner, platform, - streamOutput: false)) { + if (!await runPubGet( + package, + processRunner, + platform, + streamOutput: false, + )) { printError('${indentation}Fetching dependencies failed'); return false; } print('${indentation}Updating mocks...'); final io.ProcessResult buildRunnerResult = await processRunner.run( - 'dart', - [ - 'run', - 'build_runner', - 'build', - '--delete-conflicting-outputs' - ], - workingDir: package.directory); + 'dart', + ['run', 'build_runner', 'build', '--delete-conflicting-outputs'], + workingDir: package.directory, + ); if (buildRunnerResult.exitCode != 0) { printError( - '"dart run build_runner build" failed (${buildRunnerResult.exitCode}):\n' - '${buildRunnerResult.stdout}\n${buildRunnerResult.stderr}\n'); + '"dart run build_runner build" failed (${buildRunnerResult.exitCode}):\n' + '${buildRunnerResult.stdout}\n${buildRunnerResult.stderr}\n', + ); return false; } return true; @@ -539,8 +575,12 @@ A version with a valid format (3 numbers separated by 2 periods) must be provide } class _PubDependencyInfo { - const _PubDependencyInfo(this.type, - {required this.pinned, required this.hosted, this.constraintString}); + const _PubDependencyInfo( + this.type, { + required this.pinned, + required this.hosted, + this.constraintString, + }); final _PubDependencyType type; final bool pinned; final bool hosted; diff --git a/script/tool/lib/src/update_excerpts_command.dart b/script/tool/lib/src/update_excerpts_command.dart index 53324ecf2f4f..577b08ebfe38 100644 --- a/script/tool/lib/src/update_excerpts_command.dart +++ b/script/tool/lib/src/update_excerpts_command.dart @@ -28,7 +28,8 @@ class UpdateExcerptsCommand extends PackageLoopingCommand { }) { argParser.addFlag( _failOnChangeFlag, - help: 'Fail if the command does anything. ' + help: + 'Fail if the command does anything. ' '(Used in CI to ensure excerpts are up to date.)', ); } @@ -39,7 +40,8 @@ class UpdateExcerptsCommand extends PackageLoopingCommand { final String name = 'update-excerpts'; @override - final String description = 'Updates code excerpts in .md files, based ' + final String description = + 'Updates code excerpts in .md files, based ' 'on code from code files, via pragmas.'; @override @@ -47,8 +49,8 @@ class UpdateExcerptsCommand extends PackageLoopingCommand { @override Future runForPackage(RepositoryPackage package) async { - final List changedFiles = []; - final List errors = []; + final changedFiles = []; + final errors = []; final List markdownFiles = package.directory .listSync(recursive: true) .where((FileSystemEntity entity) { @@ -58,13 +60,17 @@ class UpdateExcerptsCommand extends PackageLoopingCommand { }) .cast() .toList(); - for (final File file in markdownFiles) { + for (final file in markdownFiles) { final _UpdateResult result = _updateExcerptsIn(file); if (result.snippetCount > 0) { - final String displayPath = - getRelativePosixPath(file, from: package.directory); - print('${indentation}Checked ${result.snippetCount} snippet(s) in ' - '$displayPath.'); + final String displayPath = getRelativePosixPath( + file, + from: package.directory, + ); + print( + '${indentation}Checked ${result.snippetCount} snippet(s) in ' + '$displayPath.', + ); } if (result.changed) { changedFiles.add(file); @@ -101,23 +107,24 @@ class UpdateExcerptsCommand extends PackageLoopingCommand { } static const String _pragma = '$'); + static final RegExp _basePattern = RegExp( + r'^ *<\?code-excerpt path-base="([^"]+)"\?>$', + ); static final RegExp _injectPattern = RegExp( r'^ *<\?code-excerpt "(?[^ ]+) \((?
[^)]+)\)"(?: plaster="(?[^"]*)")?\?>$', ); _UpdateResult _updateExcerptsIn(File file) { - bool detectedChange = false; - int snippetCount = 0; - final List errors = []; + var detectedChange = false; + var snippetCount = 0; + final errors = []; Directory pathBase = file.parent; - final StringBuffer output = StringBuffer(); - final StringBuffer existingBlock = StringBuffer(); + final output = StringBuffer(); + final existingBlock = StringBuffer(); String? language; String? excerpt; _ExcerptParseMode mode = _ExcerptParseMode.normal; - int lineNumber = 0; + var lineNumber = 0; for (final String line in file.readAsLinesSync()) { lineNumber += 1; switch (mode) { @@ -125,14 +132,16 @@ class UpdateExcerptsCommand extends PackageLoopingCommand { if (line.contains(_pragma)) { RegExpMatch? match = _basePattern.firstMatch(line); if (match != null) { - pathBase = - file.parent.childDirectory(path.normalize(match.group(1)!)); + pathBase = file.parent.childDirectory( + path.normalize(match.group(1)!), + ); } else { match = _injectPattern.firstMatch(line); if (match != null) { snippetCount++; - final String excerptPath = - path.normalize(match.namedGroup('path')!); + final String excerptPath = path.normalize( + match.namedGroup('path')!, + ); final File excerptSourceFile = pathBase.childFile(excerptPath); final String extension = path.extension(excerptSourceFile.path); switch (extension) { @@ -154,15 +163,22 @@ class UpdateExcerptsCommand extends PackageLoopingCommand { final String plaster = match.namedGroup('plaster') ?? '···'; if (!excerptSourceFile.existsSync()) { errors.add( - '${file.path}:$lineNumber: specified file "$excerptPath" (resolved to "${excerptSourceFile.path}") does not exist'); + '${file.path}:$lineNumber: specified file "$excerptPath" (resolved to "${excerptSourceFile.path}") does not exist', + ); } else { excerpt = _extractExcerpt( - excerptSourceFile, section, plaster, language, errors); + excerptSourceFile, + section, + plaster, + language, + errors, + ); } mode = _ExcerptParseMode.pragma; } else { errors.add( - '${file.path}:$lineNumber: $_pragma?> pragma does not match expected syntax or is not alone on the line'); + '${file.path}:$lineNumber: $_pragma?> pragma does not match expected syntax or is not alone on the line', + ); } } } @@ -170,12 +186,14 @@ class UpdateExcerptsCommand extends PackageLoopingCommand { case _ExcerptParseMode.pragma: if (!line.startsWith('```')) { errors.add( - '${file.path}:$lineNumber: expected code block but did not find one'); + '${file.path}:$lineNumber: expected code block but did not find one', + ); mode = _ExcerptParseMode.normal; } else { if (line.startsWith('``` ')) { errors.add( - '${file.path}:$lineNumber: code block was followed by a space character instead of the language (expected "$language")'); + '${file.path}:$lineNumber: code block was followed by a space character instead of the language (expected "$language")', + ); mode = _ExcerptParseMode.injecting; } else if (line != '```$language' && line != '```rfwtxt' && @@ -183,7 +201,8 @@ class UpdateExcerptsCommand extends PackageLoopingCommand { // We special-case rfwtxt and json because the rfw package extracts such sections from Dart files. // If we get more special cases we should think about a more general solution. errors.add( - '${file.path}:$lineNumber: code block has wrong language'); + '${file.path}:$lineNumber: code block has wrong language', + ); } mode = _ExcerptParseMode.injecting; } @@ -212,23 +231,29 @@ class UpdateExcerptsCommand extends PackageLoopingCommand { file.writeAsStringSync(output.toString()); } catch (e) { errors.add( - '${file.path}: failed to update file (${e.runtimeType}: $e)'); + '${file.path}: failed to update file (${e.runtimeType}: $e)', + ); } } } return _UpdateResult(detectedChange, snippetCount, errors); } - String _extractExcerpt(File excerptSourceFile, String section, - String plasterInside, String language, List errors) { - final List buffer = []; - bool extracting = false; - int lineNumber = 0; - int maxLength = 0; - bool found = false; - String prefix = ''; - String suffix = ''; - String padding = ''; + String _extractExcerpt( + File excerptSourceFile, + String section, + String plasterInside, + String language, + List errors, + ) { + final buffer = []; + var extracting = false; + var lineNumber = 0; + var maxLength = 0; + var found = false; + var prefix = ''; + var suffix = ''; + var padding = ''; switch (language) { case 'cc': case 'c++': @@ -254,9 +279,9 @@ class UpdateExcerptsCommand extends PackageLoopingCommand { case 'sh': prefix = '# '; } - final String startRegionMarker = '$prefix#docregion $section$suffix'; - final String endRegionMarker = '$prefix#enddocregion $section$suffix'; - final String plaster = '$prefix$padding$plasterInside$padding$suffix'; + final startRegionMarker = '$prefix#docregion $section$suffix'; + final endRegionMarker = '$prefix#enddocregion $section$suffix'; + final plaster = '$prefix$padding$plasterInside$padding$suffix'; int? indentation; for (final String excerptLine in excerptSourceFile.readAsLinesSync()) { final String trimmedLine = excerptLine.trimLeft(); @@ -268,7 +293,8 @@ class UpdateExcerptsCommand extends PackageLoopingCommand { } else { if (trimmedLine == startRegionMarker) { errors.add( - '${excerptSourceFile.path}:$lineNumber: saw "$startRegionMarker" pragma while already in a "$section" doc region'); + '${excerptSourceFile.path}:$lineNumber: saw "$startRegionMarker" pragma while already in a "$section" doc region', + ); } if (excerptLine.length > maxLength) { maxLength = excerptLine.length; @@ -291,27 +317,29 @@ class UpdateExcerptsCommand extends PackageLoopingCommand { } } if (extracting) { - errors - .add('${excerptSourceFile.path}: missing "$endRegionMarker" pragma'); + errors.add( + '${excerptSourceFile.path}: missing "$endRegionMarker" pragma', + ); } if (!found) { errors.add( - '${excerptSourceFile.path}: did not find a "$startRegionMarker" pragma'); + '${excerptSourceFile.path}: did not find a "$startRegionMarker" pragma', + ); return ''; } if (buffer.isEmpty) { errors.add('${excerptSourceFile.path}: region "$section" is empty'); return ''; } - int indent = maxLength; - for (final String line in buffer) { + var indent = maxLength; + for (final line in buffer) { if (indent == 0) { break; } if (line.isEmpty) { continue; } - for (int index = 0; index < line.length; index += 1) { + for (var index = 0; index < line.length; index += 1) { if (line[index] != ' ') { if (index < indent) { indent = index; @@ -319,8 +347,8 @@ class UpdateExcerptsCommand extends PackageLoopingCommand { } } } - final StringBuffer excerpt = StringBuffer(); - for (final String line in buffer) { + final excerpt = StringBuffer(); + for (final line in buffer) { if (line.isEmpty) { excerpt.writeln(); } else { diff --git a/script/tool/lib/src/update_min_sdk_command.dart b/script/tool/lib/src/update_min_sdk_command.dart index ed157e1bfcc9..8fe62df20bc5 100644 --- a/script/tool/lib/src/update_min_sdk_command.dart +++ b/script/tool/lib/src/update_min_sdk_command.dart @@ -15,13 +15,12 @@ const int _exitUnknownVersion = 3; /// A command to update the minimum Flutter and Dart SDKs of packages. class UpdateMinSdkCommand extends PackageLoopingCommand { /// Creates a publish metadata updater command instance. - UpdateMinSdkCommand( - super.packagesDir, { - super.gitDir, - }) { - argParser.addOption(_flutterMinFlag, - mandatory: true, - help: 'The minimum version of Flutter to set SDK constraints to.'); + UpdateMinSdkCommand(super.packagesDir, {super.gitDir}) { + argParser.addOption( + _flutterMinFlag, + mandatory: true, + help: 'The minimum version of Flutter to set SDK constraints to.', + ); } static const String _flutterMinFlag = 'flutter-min'; @@ -33,7 +32,8 @@ class UpdateMinSdkCommand extends PackageLoopingCommand { final String name = 'update-min-sdk'; @override - final String description = 'Updates the Flutter and Dart SDK minimums ' + final String description = + 'Updates the Flutter and Dart SDK minimums ' 'in pubspec.yaml to match the given Flutter version.'; @override @@ -48,10 +48,12 @@ class UpdateMinSdkCommand extends PackageLoopingCommand { _flutterMinVersion = Version.parse(getStringArg(_flutterMinFlag)); final Version? dartMinVersion = getDartSdkForFlutterSdk(_flutterMinVersion); if (dartMinVersion == null) { - printError('Dart SDK version for Flutter SDK version ' - '$_flutterMinVersion is unknown. ' - 'Please update the map for getDartSdkForFlutterSdk with the ' - 'corresponding Dart version.'); + printError( + 'Dart SDK version for Flutter SDK version ' + '$_flutterMinVersion is unknown. ' + 'Please update the map for getDartSdkForFlutterSdk with the ' + 'corresponding Dart version.', + ); throw ToolExit(_exitUnknownVersion); } _dartMinVersion = dartMinVersion; @@ -61,25 +63,28 @@ class UpdateMinSdkCommand extends PackageLoopingCommand { Future runForPackage(RepositoryPackage package) async { final Pubspec pubspec = package.parsePubspec(); - const String environmentKey = 'environment'; - const String dartSdkKey = 'sdk'; - const String flutterSdkKey = 'flutter'; + const environmentKey = 'environment'; + const dartSdkKey = 'sdk'; + const flutterSdkKey = 'flutter'; final VersionRange? dartRange = _sdkRange(pubspec, dartSdkKey); final VersionRange? flutterRange = _sdkRange(pubspec, flutterSdkKey); - final YamlEditor editablePubspec = - YamlEditor(package.pubspecFile.readAsStringSync()); + final editablePubspec = YamlEditor(package.pubspecFile.readAsStringSync()); if (dartRange != null && (dartRange.min ?? Version.none) < _dartMinVersion) { - editablePubspec - .update([environmentKey, dartSdkKey], '^$_dartMinVersion'); + editablePubspec.update([ + environmentKey, + dartSdkKey, + ], '^$_dartMinVersion'); print('${indentation}Updating Dart minimum to $_dartMinVersion'); } if (flutterRange != null && (flutterRange.min ?? Version.none) < _flutterMinVersion) { - editablePubspec.update([environmentKey, flutterSdkKey], - VersionRange(min: _flutterMinVersion, includeMin: true).toString()); + editablePubspec.update([ + environmentKey, + flutterSdkKey, + ], VersionRange(min: _flutterMinVersion, includeMin: true).toString()); print('${indentation}Updating Flutter minimum to $_flutterMinVersion'); } package.pubspecFile.writeAsStringSync(editablePubspec.toString()); diff --git a/script/tool/lib/src/update_release_info_command.dart b/script/tool/lib/src/update_release_info_command.dart index d139d173a069..0224596f875f 100644 --- a/script/tool/lib/src/update_release_info_command.dart +++ b/script/tool/lib/src/update_release_info_command.dart @@ -33,33 +33,36 @@ enum _ChangelogUpdateState { /// A command to update the changelog, and optionally version, of packages. class UpdateReleaseInfoCommand extends PackageLoopingCommand { /// Creates a publish metadata updater command instance. - UpdateReleaseInfoCommand( - super.packagesDir, { - super.gitDir, - }) { - argParser.addOption(_changelogFlag, - mandatory: true, - help: 'The changelog entry to add. ' - 'Each line will be a separate list entry.'); - argParser.addOption(_versionTypeFlag, - mandatory: true, - help: 'The version change level', - allowed: [ - _versionNext, - _versionMinimal, - _versionBugfix, - _versionMinor, - ], - allowedHelp: { - _versionNext: - 'No version change; just adds a NEXT entry to the changelog.', - _versionBugfix: 'Increments the bugfix version.', - _versionMinor: 'Increments the minor version.', - _versionMinimal: 'Depending on the changes to each package: ' - 'increments the bugfix version (for publishable changes), ' - "uses NEXT (for changes that don't need to be published), " - 'or skips (if no changes).', - }); + UpdateReleaseInfoCommand(super.packagesDir, {super.gitDir}) { + argParser.addOption( + _changelogFlag, + mandatory: true, + help: + 'The changelog entry to add. ' + 'Each line will be a separate list entry.', + ); + argParser.addOption( + _versionTypeFlag, + mandatory: true, + help: 'The version change level', + allowed: [ + _versionNext, + _versionMinimal, + _versionBugfix, + _versionMinor, + ], + allowedHelp: { + _versionNext: + 'No version change; just adds a NEXT entry to the changelog.', + _versionBugfix: 'Increments the bugfix version.', + _versionMinor: 'Increments the minor version.', + _versionMinimal: + 'Depending on the changes to each package: ' + 'increments the bugfix version (for publishable changes), ' + "uses NEXT (for changes that don't need to be published), " + 'or skips (if no changes).', + }, + ); } static const String _changelogFlag = 'changelog'; @@ -79,7 +82,8 @@ class UpdateReleaseInfoCommand extends PackageLoopingCommand { final String name = 'update-release-info'; @override - final String description = 'Updates CHANGELOG.md files, and optionally the ' + final String description = + 'Updates CHANGELOG.md files, and optionally the ' 'version in pubspec.yaml, in a way that is consistent with version-check ' 'enforcement.'; @@ -116,12 +120,18 @@ class UpdateReleaseInfoCommand extends PackageLoopingCommand { // needed. if (versionChange == null && getStringArg(_versionTypeFlag) == _versionMinimal) { - final Directory gitRoot = - packagesDir.fileSystem.directory((await gitDir).path); - final String relativePackagePath = - getRelativePosixPath(package.directory, from: gitRoot); - final PackageChangeState state = await checkPackageChangeState(package, - changedPaths: changedFiles, relativePackagePath: relativePackagePath); + final Directory gitRoot = packagesDir.fileSystem.directory( + (await gitDir).path, + ); + final String relativePackagePath = getRelativePosixPath( + package.directory, + from: gitRoot, + ); + final PackageChangeState state = await checkPackageChangeState( + package, + changedPaths: changedFiles, + relativePackagePath: relativePackagePath, + ); if (!state.hasChanges) { return PackageResult.skip('No changes to package'); @@ -135,11 +145,14 @@ class UpdateReleaseInfoCommand extends PackageLoopingCommand { } if (versionChange != null) { - final Version? updatedVersion = - _updatePubspecVersion(package, versionChange); + final Version? updatedVersion = _updatePubspecVersion( + package, + versionChange, + ); if (updatedVersion == null) { - return PackageResult.fail( - ['Could not determine current version.']); + return PackageResult.fail([ + 'Could not determine current version.', + ]); } nextVersionString = updatedVersion.toString(); print('${indentation}Incremented version to $nextVersionString.'); @@ -147,8 +160,10 @@ class UpdateReleaseInfoCommand extends PackageLoopingCommand { nextVersionString = 'NEXT'; } - final _ChangelogUpdateOutcome updateOutcome = - _updateChangelog(package, nextVersionString); + final _ChangelogUpdateOutcome updateOutcome = _updateChangelog( + package, + nextVersionString, + ); switch (updateOutcome) { case _ChangelogUpdateOutcome.addedSection: print('${indentation}Added a $nextVersionString section.'); @@ -162,18 +177,20 @@ class UpdateReleaseInfoCommand extends PackageLoopingCommand { } _ChangelogUpdateOutcome _updateChangelog( - RepositoryPackage package, String version) { + RepositoryPackage package, + String version, + ) { if (!package.changelogFile.existsSync()) { printError('${indentation}Missing CHANGELOG.md.'); return _ChangelogUpdateOutcome.failed; } - final String newHeader = '## $version'; - final RegExp listItemPattern = RegExp(r'^(\s*[-*])'); + final newHeader = '## $version'; + final listItemPattern = RegExp(r'^(\s*[-*])'); - final StringBuffer newChangelog = StringBuffer(); + final newChangelog = StringBuffer(); _ChangelogUpdateState state = _ChangelogUpdateState.findingFirstSection; - bool updatedExistingSection = false; + var updatedExistingSection = false; for (final String line in package.changelogFile.readAsLinesSync()) { switch (state) { @@ -253,7 +270,9 @@ class UpdateReleaseInfoCommand extends PackageLoopingCommand { /// Updates the version in [package]'s pubspec according to [type], returning /// the new version, or null if there was an error updating the version. Version? _updatePubspecVersion( - RepositoryPackage package, _VersionIncrementType type) { + RepositoryPackage package, + _VersionIncrementType type, + ) { final Pubspec pubspec = package.parsePubspec(); final Version? currentVersion = pubspec.version; if (currentVersion == null) { @@ -270,8 +289,7 @@ class UpdateReleaseInfoCommand extends PackageLoopingCommand { final Version newVersion = _nextVersion(currentVersion, adjustedType); // Write the new version to the pubspec. - final YamlEditor editablePubspec = - YamlEditor(package.pubspecFile.readAsStringSync()); + final editablePubspec = YamlEditor(package.pubspecFile.readAsStringSync()); editablePubspec.update(['version'], newVersion.toString()); package.pubspecFile.writeAsStringSync(editablePubspec.toString()); @@ -285,10 +303,15 @@ class UpdateReleaseInfoCommand extends PackageLoopingCommand { case _VersionIncrementType.bugfix: return version.nextPatch; case _VersionIncrementType.build: - final int buildNumber = - version.build.isEmpty ? 0 : version.build.first as int; - return Version(version.major, version.minor, version.patch, - build: '${buildNumber + 1}'); + final buildNumber = version.build.isEmpty + ? 0 + : version.build.first as int; + return Version( + version.major, + version.minor, + version.patch, + build: '${buildNumber + 1}', + ); } } } diff --git a/script/tool/lib/src/version_check_command.dart b/script/tool/lib/src/version_check_command.dart index 4d147cb92baa..e91f94c67237 100644 --- a/script/tool/lib/src/version_check_command.dart +++ b/script/tool/lib/src/version_check_command.dart @@ -61,22 +61,21 @@ Map getAllowedNextVersions( Version version, { required Version newVersion, }) { - final Map allowedNextVersions = - { + final allowedNextVersions = { version.nextMajor: NextVersionType.BREAKING_MAJOR, version.nextMinor: NextVersionType.MINOR, version.nextPatch: NextVersionType.PATCH, }; if (version.major < 1 && newVersion.major < 1) { - int nextBuildNumber = -1; + var nextBuildNumber = -1; if (version.build.isEmpty) { nextBuildNumber = 1; } else { - final int currentBuildNumber = version.build.first as int; + final currentBuildNumber = version.build.first as int; nextBuildNumber = currentBuildNumber + 1; } - final Version nextBuildVersion = Version( + final nextBuildVersion = Version( version.major, version.minor, version.patch, @@ -100,34 +99,45 @@ class VersionCheckCommand extends PackageLoopingCommand { super.platform, super.gitDir, http.Client? httpClient, - }) : _pubVersionFinder = - PubVersionFinder(httpClient: httpClient ?? http.Client()) { + }) : _pubVersionFinder = PubVersionFinder( + httpClient: httpClient ?? http.Client(), + ) { argParser.addFlag( _againstPubFlag, - help: 'Whether the version check should run against the version on pub.\n' + help: + 'Whether the version check should run against the version on pub.\n' 'Defaults to false, which means the version check only run against ' 'the previous version in code.', ); - argParser.addOption(_prLabelsArg, - help: 'A comma-separated list of labels associated with this PR, ' - 'if applicable.\n\n' - 'If supplied, this may be to allow overrides to some version ' - 'checks.'); - argParser.addFlag(_checkForMissingChanges, - help: 'Validates that changes to packages include CHANGELOG and ' - 'version changes unless they meet an established exemption.\n\n' - 'If used with --$_prLabelsArg, this is should only be ' - 'used in pre-submit CI checks, to prevent post-submit breakage ' - 'when labels are no longer applicable.', - hide: true); - argParser.addFlag(_ignorePlatformInterfaceBreaks, - help: 'Bypasses the check that platform interfaces do not contain ' - 'breaking changes.\n\n' - 'This is only intended for use in post-submit CI checks, to ' - 'prevent post-submit breakage when overriding the check with ' - 'labels. Pre-submit checks should always use ' - '--$_prLabelsArg instead.', - hide: true); + argParser.addOption( + _prLabelsArg, + help: + 'A comma-separated list of labels associated with this PR, ' + 'if applicable.\n\n' + 'If supplied, this may be to allow overrides to some version ' + 'checks.', + ); + argParser.addFlag( + _checkForMissingChanges, + help: + 'Validates that changes to packages include CHANGELOG and ' + 'version changes unless they meet an established exemption.\n\n' + 'If used with --$_prLabelsArg, this is should only be ' + 'used in pre-submit CI checks, to prevent post-submit breakage ' + 'when labels are no longer applicable.', + hide: true, + ); + argParser.addFlag( + _ignorePlatformInterfaceBreaks, + help: + 'Bypasses the check that platform interfaces do not contain ' + 'breaking changes.\n\n' + 'This is only intended for use in post-submit CI checks, to ' + 'prevent post-submit breakage when overriding the check with ' + 'labels. Pre-submit checks should always use ' + '--$_prLabelsArg instead.', + hide: true, + ); } static const String _againstPubFlag = 'against-pub'; @@ -191,18 +201,22 @@ class VersionCheckCommand extends PackageLoopingCommand { final Version? currentPubspecVersion = pubspec.version; if (currentPubspecVersion == null) { - printError('${indentation}No version found in pubspec.yaml. A package ' - 'that intentionally has no version should be marked ' - '"publish_to: none".'); + printError( + '${indentation}No version found in pubspec.yaml. A package ' + 'that intentionally has no version should be marked ' + '"publish_to: none".', + ); // No remaining checks make sense, so fail immediately. return PackageResult.fail(['No pubspec.yaml version.']); } - final List errors = []; + final errors = []; bool versionChanged; - final _CurrentVersionState versionState = - await _getVersionState(package, pubspec: pubspec); + final _CurrentVersionState versionState = await _getVersionState( + package, + pubspec: pubspec, + ); switch (versionState) { case _CurrentVersionState.unchanged: versionChanged = false; @@ -218,8 +232,11 @@ class VersionCheckCommand extends PackageLoopingCommand { errors.add('Unable to determine previous version.'); } - if (!(await _validateChangelogVersion(package, - pubspec: pubspec, pubspecVersionState: versionState))) { + if (!(await _validateChangelogVersion( + package, + pubspec: pubspec, + pubspecVersionState: versionState, + ))) { errors.add('CHANGELOG.md failed validation.'); } @@ -269,8 +286,10 @@ ${indentation}HTTP response: ${pubVersionFinderResponse.httpResponse.body} /// Returns the version of [package] from git at the base comparison hash. Future _getPreviousVersionFromGit(RepositoryPackage package) async { final File pubspecFile = package.pubspecFile; - final String relativePath = - path.relative(pubspecFile.absolute.path, from: (await gitDir).path); + final String relativePath = path.relative( + pubspecFile.absolute.path, + from: (await gitDir).path, + ); // Use Posix-style paths for git. final String gitPath = path.style == p.Style.windows ? p.posix.joinAll(path.split(relativePath)) @@ -296,7 +315,8 @@ ${indentation}HTTP response: ${pubVersionFinderResponse.httpResponse.body} } if (previousVersion != Version.none) { print( - '$indentation${pubspec.name}: Current largest version on pub: $previousVersion'); + '$indentation${pubspec.name}: Current largest version on pub: $previousVersion', + ); } } else { previousVersionSource = baseSha; @@ -304,10 +324,13 @@ ${indentation}HTTP response: ${pubVersionFinderResponse.httpResponse.body} await _getPreviousVersionFromGit(package) ?? Version.none; } if (previousVersion == Version.none) { - print('${indentation}Unable to find previous version ' - '${getBoolArg(_againstPubFlag) ? 'on pub server' : 'at git base'}.'); + print( + '${indentation}Unable to find previous version ' + '${getBoolArg(_againstPubFlag) ? 'on pub server' : 'at git base'}.', + ); logWarning( - '${indentation}If this package is not new, something has gone wrong.'); + '${indentation}If this package is not new, something has gone wrong.', + ); return _CurrentVersionState.newPackage; } @@ -322,9 +345,13 @@ ${indentation}HTTP response: ${pubVersionFinderResponse.httpResponse.body} // to be a revert rather than a typo by checking that the transition // from the lower version to the new version would have been valid. if (_shouldAllowVersionChange( - oldVersion: currentVersion, newVersion: previousVersion)) { - logWarning('${indentation}New version is lower than previous version. ' - 'This is assumed to be a revert.'); + oldVersion: currentVersion, + newVersion: previousVersion, + )) { + logWarning( + '${indentation}New version is lower than previous version. ' + 'This is assumed to be a revert.', + ); return _CurrentVersionState.validRevert; } } @@ -333,29 +360,36 @@ ${indentation}HTTP response: ${pubVersionFinderResponse.httpResponse.body} getAllowedNextVersions(previousVersion, newVersion: currentVersion); if (_shouldAllowVersionChange( - oldVersion: previousVersion, newVersion: currentVersion)) { + oldVersion: previousVersion, + newVersion: currentVersion, + )) { print('$indentation$previousVersion -> $currentVersion'); } else { - printError('${indentation}Incorrectly updated version.\n' - '${indentation}HEAD: $currentVersion, $previousVersionSource: $previousVersion.\n' - '${indentation}Allowed versions: $allowedNextVersions'); + printError( + '${indentation}Incorrectly updated version.\n' + '${indentation}HEAD: $currentVersion, $previousVersionSource: $previousVersion.\n' + '${indentation}Allowed versions: $allowedNextVersions', + ); return _CurrentVersionState.invalidChange; } // Check whether the version (or for a pre-release, the version that // pre-release would eventually be released as) is a breaking change, and // if so, validate it. - final Version targetReleaseVersion = - currentVersion.isPreRelease ? currentVersion.nextPatch : currentVersion; + final Version targetReleaseVersion = currentVersion.isPreRelease + ? currentVersion.nextPatch + : currentVersion; if (allowedNextVersions[targetReleaseVersion] == NextVersionType.BREAKING_MAJOR && !_validateBreakingChange(package)) { - printError('${indentation}Breaking change detected.\n' - '${indentation}Breaking changes to platform interfaces are not ' - 'allowed without explicit justification.\n' - '${indentation}See ' - 'https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md ' - 'for more information.'); + printError( + '${indentation}Breaking change detected.\n' + '${indentation}Breaking changes to platform interfaces are not ' + 'allowed without explicit justification.\n' + '${indentation}See ' + 'https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md ' + 'for more information.', + ); return _CurrentVersionState.invalidChange; } @@ -390,13 +424,14 @@ ${indentation}HTTP response: ${pubVersionFinderResponse.httpResponse.body} String? versionString = firstLineWithText?.split(' ').last; String? leadingMarkdown = firstLineWithText?.split(' ').first; - final String badNextErrorMessage = '${indentation}When bumping the version ' + final badNextErrorMessage = + '${indentation}When bumping the version ' 'for release, the NEXT section should be incorporated into the new ' "version's release notes."; // Skip validation for the special NEXT version that's used to accumulate // changes that don't warrant publishing on their own. - final bool hasNextSection = versionString == 'NEXT'; + final hasNextSection = versionString == 'NEXT'; if (hasNextSection) { // NEXT should not be present in a commit that increases the version. if (pubspecVersionState == _CurrentVersionState.validIncrease || @@ -405,7 +440,8 @@ ${indentation}HTTP response: ${pubVersionFinderResponse.httpResponse.body} return false; } print( - '${indentation}Found NEXT; validating next version in the CHANGELOG.'); + '${indentation}Found NEXT; validating next version in the CHANGELOG.', + ); // Ensure that the version in pubspec hasn't changed without updating // CHANGELOG. That means the next version entry in the CHANGELOG should // pass the normal validation. @@ -420,12 +456,14 @@ ${indentation}HTTP response: ${pubVersionFinderResponse.httpResponse.body} } } - final bool validLeadingMarkdown = leadingMarkdown == '##'; + final validLeadingMarkdown = leadingMarkdown == '##'; if (versionString == null || !validLeadingMarkdown) { printError('${indentation}Unable to find a version in CHANGELOG.md'); - print('${indentation}The current version should be on a line starting ' - 'with "## ", either on the first non-empty line or after a "## NEXT" ' - 'section.'); + print( + '${indentation}The current version should be on a line starting ' + 'with "## ", either on the first non-empty line or after a "## NEXT" ' + 'section.', + ); return false; } @@ -448,7 +486,7 @@ ${indentation}The first version listed in CHANGELOG.md is $fromChangeLog. // If NEXT wasn't the first section, it should not exist at all. if (!hasNextSection) { - final RegExp nextRegex = RegExp(r'^#+\s*NEXT\s*$'); + final nextRegex = RegExp(r'^#+\s*NEXT\s*$'); if (lines.any((String line) => nextRegex.hasMatch(line))) { printError(badNextErrorMessage); return false; @@ -478,15 +516,17 @@ ${indentation}The first version listed in CHANGELOG.md is $fromChangeLog. if (getBoolArg(_ignorePlatformInterfaceBreaks)) { logWarning( - '${indentation}Allowing breaking change to ${package.displayName} ' - 'due to --$_ignorePlatformInterfaceBreaks'); + '${indentation}Allowing breaking change to ${package.displayName} ' + 'due to --$_ignorePlatformInterfaceBreaks', + ); return true; } if (_prLabels.contains(_breakingChangeOverrideLabel)) { logWarning( - '${indentation}Allowing breaking change to ${package.displayName} ' - 'due to the "$_breakingChangeOverrideLabel" label.'); + '${indentation}Allowing breaking change to ${package.displayName} ' + 'due to the "$_breakingChangeOverrideLabel" label.', + ); return true; } @@ -504,8 +544,10 @@ ${indentation}The first version listed in CHANGELOG.md is $fromChangeLog. } /// Returns true if the given version transition should be allowed. - bool _shouldAllowVersionChange( - {required Version oldVersion, required Version newVersion}) { + bool _shouldAllowVersionChange({ + required Version oldVersion, + required Version newVersion, + }) { // Get the non-pre-release next version mapping. final Map allowedNextVersions = getAllowedNextVersions(oldVersion, newVersion: newVersion); @@ -533,62 +575,76 @@ ${indentation}The first version listed in CHANGELOG.md is $fromChangeLog. // Find the relative path to the current package, as it would appear at the // beginning of a path reported by changedFiles (which always uses // Posix paths). - final Directory gitRoot = - packagesDir.fileSystem.directory((await gitDir).path); - final String relativePackagePath = - getRelativePosixPath(package.directory, from: gitRoot); + final Directory gitRoot = packagesDir.fileSystem.directory( + (await gitDir).path, + ); + final String relativePackagePath = getRelativePosixPath( + package.directory, + from: gitRoot, + ); - final PackageChangeState state = await checkPackageChangeState(package, - changedPaths: changedFiles, - relativePackagePath: relativePackagePath, - git: await retrieveVersionFinder()); + final PackageChangeState state = await checkPackageChangeState( + package, + changedPaths: changedFiles, + relativePackagePath: relativePackagePath, + git: await retrieveVersionFinder(), + ); if (!state.hasChanges) { return null; } - bool missingVersionChange = false; - bool missingChangelogChange = false; + var missingVersionChange = false; + var missingChangelogChange = false; if (state.needsVersionChange) { if (_prLabels.contains(_missingVersionChangeOverrideLabel)) { - logWarning('Ignoring lack of version change due to the ' - '"$_missingVersionChangeOverrideLabel" label.'); + logWarning( + 'Ignoring lack of version change due to the ' + '"$_missingVersionChangeOverrideLabel" label.', + ); } else { missingVersionChange = true; printError( - 'No version change found, but the change to this package could ' - 'not be verified to be exempt\n' - 'from version changes according to repository policy.\n' - 'If this is a false positive, please comment in ' - 'the PR to explain why the PR\n' - 'is exempt, and add (or ask your reviewer to add) the ' - '"$_missingVersionChangeOverrideLabel" label.\n'); + 'No version change found, but the change to this package could ' + 'not be verified to be exempt\n' + 'from version changes according to repository policy.\n' + 'If this is a false positive, please comment in ' + 'the PR to explain why the PR\n' + 'is exempt, and add (or ask your reviewer to add) the ' + '"$_missingVersionChangeOverrideLabel" label.\n', + ); } } if (!state.hasChangelogChange && state.needsChangelogChange) { if (_prLabels.contains(_missingChangelogChangeOverrideLabel)) { - logWarning('Ignoring lack of CHANGELOG update due to the ' - '"$_missingChangelogChangeOverrideLabel" label.'); + logWarning( + 'Ignoring lack of CHANGELOG update due to the ' + '"$_missingChangelogChangeOverrideLabel" label.', + ); } else { missingChangelogChange = true; - printError('No CHANGELOG change found.\n' - 'If this PR needs an exemption from the standard policy of listing ' - 'all changes in the CHANGELOG,\n' - 'comment in the PR to explain why the PR is exempt, and add (or ' - 'ask your reviewer to add) the\n' - '"$_missingChangelogChangeOverrideLabel" label.\n' - 'Otherwise, please add a NEXT entry in the CHANGELOG as described in ' - 'the contributing guide.\n'); + printError( + 'No CHANGELOG change found.\n' + 'If this PR needs an exemption from the standard policy of listing ' + 'all changes in the CHANGELOG,\n' + 'comment in the PR to explain why the PR is exempt, and add (or ' + 'ask your reviewer to add) the\n' + '"$_missingChangelogChangeOverrideLabel" label.\n' + 'Otherwise, please add a NEXT entry in the CHANGELOG as described in ' + 'the contributing guide.\n', + ); } } if (missingVersionChange && missingChangelogChange) { - printError('If this PR is not exempt, you can update version and ' - 'CHANGELOG with the "update-release-info" command.\\\n' - 'See here for an example: ' - 'https://github.com/flutter/packages/blob/main/script/tool/README.md#update-changelog-and-version\\\n' - 'For more details on versioning, check the contributing guide.'); + printError( + 'If this PR is not exempt, you can update version and ' + 'CHANGELOG with the "update-release-info" command.\\\n' + 'See here for an example: ' + 'https://github.com/flutter/packages/blob/main/script/tool/README.md#update-changelog-and-version\\\n' + 'For more details on versioning, check the contributing guide.', + ); } if (missingVersionChange) { return 'Missing version change'; diff --git a/script/tool/pubspec.yaml b/script/tool/pubspec.yaml index 7bd5de4dde38..f351c6b757fa 100644 --- a/script/tool/pubspec.yaml +++ b/script/tool/pubspec.yaml @@ -31,4 +31,4 @@ dev_dependencies: mockito: ^5.4.4 environment: - sdk: ^3.1.0 + sdk: ^3.8.0 diff --git a/script/tool/test/analyze_command_test.dart b/script/tool/test/analyze_command_test.dart index ffc026b31a91..7ac6f4baa686 100644 --- a/script/tool/test/analyze_command_test.dart +++ b/script/tool/test/analyze_command_test.dart @@ -25,7 +25,7 @@ void main() { final GitDir gitDir; (:packagesDir, :processRunner, :gitProcessRunner, :gitDir) = configureBaseCommandMocks(platform: mockPlatform); - final AnalyzeCommand analyzeCommand = AnalyzeCommand( + final analyzeCommand = AnalyzeCommand( packagesDir, processRunner: processRunner, gitDir: gitDir, @@ -40,20 +40,23 @@ void main() { createFakePackage('a', packagesDir); await expectLater( - () => runCapturingPrint(runner, ['analyze', '--no-dart']), - throwsA(isA())); + () => runCapturingPrint(runner, ['analyze', '--no-dart']), + throwsA(isA()), + ); }); group('result aggregation', () { test('repeorts failure if any analysis fails', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin1', packagesDir, extraFiles: [ - 'example/android/gradlew', - ], platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline), - platformIOS: const PlatformDetails(PlatformSupport.inline), - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin1', + packagesDir, + extraFiles: ['example/android/gradlew'], + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + platformIOS: const PlatformDetails(PlatformSupport.inline), + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); // Simulate Android analysis failure only. final String gradlewPath = plugin @@ -68,19 +71,20 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['analyze', '--android', '--ios', '--macos'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['analyze', '--android', '--ios', '--macos'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder( - [ - contains('The following packages had errors:'), - ], - )); + output, + containsAllInOrder([ + contains('The following packages had errors:'), + ]), + ); }); test('reports skip if everything is skipped', () async { @@ -94,20 +98,19 @@ void main() { '--macos', ]); - expect( - output, - containsAllInOrder([ - contains('SKIPPING:'), - ])); + expect(output, containsAllInOrder([contains('SKIPPING:')])); expect(processRunner.recordedCalls, orderedEquals([])); }); test('reports success for a mixture of skip and success', () async { - createFakePlugin('plugin', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline) - }); + createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final List output = await runCapturingPrint(runner, [ 'analyze', @@ -118,15 +121,13 @@ void main() { ]); expect( - output, - containsAllInOrder([ - contains('No issues found'), - ])); + output, + containsAllInOrder([contains('No issues found')]), + ); expect( - output, - isNot(containsAllInOrder([ - contains('SKIPPING:'), - ]))); + output, + isNot(containsAllInOrder([contains('SKIPPING:')])), + ); }); }); @@ -138,15 +139,20 @@ void main() { await runCapturingPrint(runner, ['analyze']); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall('flutter', const ['pub', 'get'], package1.path), - ProcessCall('dart', const ['analyze', '--fatal-infos'], - package1.path), - ProcessCall('flutter', const ['pub', 'get'], plugin2.path), - ProcessCall('dart', const ['analyze', '--fatal-infos'], - plugin2.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const ['pub', 'get'], package1.path), + ProcessCall('dart', const [ + 'analyze', + '--fatal-infos', + ], package1.path), + ProcessCall('flutter', const ['pub', 'get'], plugin2.path), + ProcessCall('dart', const [ + 'analyze', + '--fatal-infos', + ], plugin2.path), + ]), + ); }); test('skips flutter pub get for examples', () async { @@ -155,134 +161,171 @@ void main() { await runCapturingPrint(runner, ['analyze']); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall('flutter', const ['pub', 'get'], plugin1.path), - ProcessCall('dart', const ['analyze', '--fatal-infos'], - plugin1.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const ['pub', 'get'], plugin1.path), + ProcessCall('dart', const [ + 'analyze', + '--fatal-infos', + ], plugin1.path), + ]), + ); }); test('runs flutter pub get for non-example subpackages', () async { final RepositoryPackage mainPackage = createFakePackage('a', packagesDir); - final Directory otherPackagesDir = - mainPackage.directory.childDirectory('other_packages'); - final RepositoryPackage subpackage1 = - createFakePackage('subpackage1', otherPackagesDir); - final RepositoryPackage subpackage2 = - createFakePackage('subpackage2', otherPackagesDir); + final Directory otherPackagesDir = mainPackage.directory.childDirectory( + 'other_packages', + ); + final RepositoryPackage subpackage1 = createFakePackage( + 'subpackage1', + otherPackagesDir, + ); + final RepositoryPackage subpackage2 = createFakePackage( + 'subpackage2', + otherPackagesDir, + ); await runCapturingPrint(runner, ['analyze']); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'flutter', const ['pub', 'get'], mainPackage.path), - ProcessCall( - 'flutter', const ['pub', 'get'], subpackage1.path), - ProcessCall( - 'flutter', const ['pub', 'get'], subpackage2.path), - ProcessCall('dart', const ['analyze', '--fatal-infos'], - mainPackage.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const [ + 'pub', + 'get', + ], mainPackage.path), + ProcessCall('flutter', const [ + 'pub', + 'get', + ], subpackage1.path), + ProcessCall('flutter', const [ + 'pub', + 'get', + ], subpackage2.path), + ProcessCall('dart', const [ + 'analyze', + '--fatal-infos', + ], mainPackage.path), + ]), + ); }); test('passes lib/ directory with --lib-only', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); await runCapturingPrint(runner, ['analyze', '--lib-only']); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall('flutter', const ['pub', 'get'], package.path), - ProcessCall( - 'dart', - const ['analyze', '--fatal-infos', 'lib'], - package.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const ['pub', 'get'], package.path), + ProcessCall('dart', const [ + 'analyze', + '--fatal-infos', + 'lib', + ], package.path), + ]), + ); }); test('skips when missing lib/ directory with --lib-only', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); package.libDirectory.deleteSync(); - final List output = - await runCapturingPrint(runner, ['analyze', '--lib-only']); + final List output = await runCapturingPrint(runner, [ + 'analyze', + '--lib-only', + ]); expect(processRunner.recordedCalls, isEmpty); expect( output, - containsAllInOrder([ - contains('SKIPPING: No lib/ directory'), - ]), + containsAllInOrder([contains('SKIPPING: No lib/ directory')]), ); }); test( - 'does not run flutter pub get for non-example subpackages with --lib-only', - () async { - final RepositoryPackage mainPackage = createFakePackage('a', packagesDir); - final Directory otherPackagesDir = - mainPackage.directory.childDirectory('other_packages'); - createFakePackage('subpackage1', otherPackagesDir); - createFakePackage('subpackage2', otherPackagesDir); + 'does not run flutter pub get for non-example subpackages with --lib-only', + () async { + final RepositoryPackage mainPackage = createFakePackage( + 'a', + packagesDir, + ); + final Directory otherPackagesDir = mainPackage.directory.childDirectory( + 'other_packages', + ); + createFakePackage('subpackage1', otherPackagesDir); + createFakePackage('subpackage2', otherPackagesDir); - await runCapturingPrint(runner, ['analyze', '--lib-only']); + await runCapturingPrint(runner, ['analyze', '--lib-only']); - expect( + expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - 'flutter', const ['pub', 'get'], mainPackage.path), - ProcessCall( - 'dart', - const ['analyze', '--fatal-infos', 'lib'], - mainPackage.path), - ])); - }); + ProcessCall('flutter', const [ + 'pub', + 'get', + ], mainPackage.path), + ProcessCall('dart', const [ + 'analyze', + '--fatal-infos', + 'lib', + ], mainPackage.path), + ]), + ); + }, + ); test("don't elide a non-contained example package", () async { final RepositoryPackage plugin1 = createFakePlugin('a', packagesDir); - final RepositoryPackage plugin2 = - createFakePlugin('example', packagesDir); + final RepositoryPackage plugin2 = createFakePlugin( + 'example', + packagesDir, + ); await runCapturingPrint(runner, ['analyze']); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall('flutter', const ['pub', 'get'], plugin1.path), - ProcessCall('dart', const ['analyze', '--fatal-infos'], - plugin1.path), - ProcessCall('flutter', const ['pub', 'get'], plugin2.path), - ProcessCall('dart', const ['analyze', '--fatal-infos'], - plugin2.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const ['pub', 'get'], plugin1.path), + ProcessCall('dart', const [ + 'analyze', + '--fatal-infos', + ], plugin1.path), + ProcessCall('flutter', const ['pub', 'get'], plugin2.path), + ProcessCall('dart', const [ + 'analyze', + '--fatal-infos', + ], plugin2.path), + ]), + ); }); test('uses a separate analysis sdk', () async { final RepositoryPackage plugin = createFakePlugin('a', packagesDir); - await runCapturingPrint( - runner, ['analyze', '--analysis-sdk', 'foo/bar/baz']); + await runCapturingPrint(runner, [ + 'analyze', + '--analysis-sdk', + 'foo/bar/baz', + ]); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - 'flutter', - const ['pub', 'get'], - plugin.path, - ), - ProcessCall( - 'foo/bar/baz/bin/dart', - const ['analyze', '--fatal-infos'], - plugin.path, - ), + ProcessCall('flutter', const ['pub', 'get'], plugin.path), + ProcessCall('foo/bar/baz/bin/dart', const [ + 'analyze', + '--fatal-infos', + ], plugin.path), ]), ); }); @@ -295,154 +338,211 @@ void main() { expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - 'flutter', - const ['pub', 'downgrade'], - plugin.path, - ), - ProcessCall( - 'flutter', - const ['pub', 'get'], - plugin.path, - ), - ProcessCall( - 'dart', - const ['analyze', '--fatal-infos'], - plugin.path, - ), + ProcessCall('flutter', const [ + 'pub', + 'downgrade', + ], plugin.path), + ProcessCall('flutter', const ['pub', 'get'], plugin.path), + ProcessCall('dart', const [ + 'analyze', + '--fatal-infos', + ], plugin.path), ]), ); }); group('verifies analysis settings', () { test('fails analysis_options.yaml', () async { - createFakePlugin('foo', packagesDir, - extraFiles: ['analysis_options.yaml']); + createFakePlugin( + 'foo', + packagesDir, + extraFiles: ['analysis_options.yaml'], + ); Error? commandError; final List output = await runCapturingPrint( - runner, ['analyze'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['analyze'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - 'Found an extra analysis_options.yaml at /packages/foo/analysis_options.yaml'), - contains(' foo:\n' - ' Unexpected local analysis options'), + 'Found an extra analysis_options.yaml at /packages/foo/analysis_options.yaml', + ), + contains( + ' foo:\n' + ' Unexpected local analysis options', + ), ]), ); }); test('fails .analysis_options', () async { - createFakePlugin('foo', packagesDir, - extraFiles: ['.analysis_options']); + createFakePlugin( + 'foo', + packagesDir, + extraFiles: ['.analysis_options'], + ); Error? commandError; final List output = await runCapturingPrint( - runner, ['analyze'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['analyze'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - 'Found an extra analysis_options.yaml at /packages/foo/.analysis_options'), - contains(' foo:\n' - ' Unexpected local analysis options'), + 'Found an extra analysis_options.yaml at /packages/foo/.analysis_options', + ), + contains( + ' foo:\n' + ' Unexpected local analysis options', + ), ]), ); }); test('takes an allow list', () async { - final RepositoryPackage plugin = createFakePlugin('foo', packagesDir, - extraFiles: ['analysis_options.yaml']); + final RepositoryPackage plugin = createFakePlugin( + 'foo', + packagesDir, + extraFiles: ['analysis_options.yaml'], + ); - await runCapturingPrint( - runner, ['analyze', '--custom-analysis', 'foo']); + await runCapturingPrint(runner, [ + 'analyze', + '--custom-analysis', + 'foo', + ]); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall('flutter', const ['pub', 'get'], plugin.path), - ProcessCall('dart', const ['analyze', '--fatal-infos'], - plugin.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const ['pub', 'get'], plugin.path), + ProcessCall('dart', const [ + 'analyze', + '--fatal-infos', + ], plugin.path), + ]), + ); }); - test('ignores analysis options in the plugin .symlinks directory', - () async { - final RepositoryPackage plugin = createFakePlugin('foo', packagesDir, - extraFiles: ['analysis_options.yaml']); - final RepositoryPackage includingPackage = - createFakePlugin('bar', packagesDir); - // Simulate the local state of having built 'bar' if it includes 'foo'. - includingPackage.directory - .childDirectory('example') - .childDirectory('ios') - .childLink('.symlinks') - .createSync(plugin.directory.path, recursive: true); - - await runCapturingPrint( - runner, ['analyze', '--custom-analysis', 'foo']); - }); + test( + 'ignores analysis options in the plugin .symlinks directory', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'foo', + packagesDir, + extraFiles: ['analysis_options.yaml'], + ); + final RepositoryPackage includingPackage = createFakePlugin( + 'bar', + packagesDir, + ); + // Simulate the local state of having built 'bar' if it includes 'foo'. + includingPackage.directory + .childDirectory('example') + .childDirectory('ios') + .childLink('.symlinks') + .createSync(plugin.directory.path, recursive: true); + + await runCapturingPrint(runner, [ + 'analyze', + '--custom-analysis', + 'foo', + ]); + }, + ); test('takes an allow config file', () async { - final RepositoryPackage plugin = createFakePlugin('foo', packagesDir, - extraFiles: ['analysis_options.yaml']); + final RepositoryPackage plugin = createFakePlugin( + 'foo', + packagesDir, + extraFiles: ['analysis_options.yaml'], + ); final File allowFile = packagesDir.childFile('custom.yaml'); allowFile.writeAsStringSync('- foo'); - await runCapturingPrint( - runner, ['analyze', '--custom-analysis', allowFile.path]); + await runCapturingPrint(runner, [ + 'analyze', + '--custom-analysis', + allowFile.path, + ]); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall('flutter', const ['pub', 'get'], plugin.path), - ProcessCall('dart', const ['analyze', '--fatal-infos'], - plugin.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const ['pub', 'get'], plugin.path), + ProcessCall('dart', const [ + 'analyze', + '--fatal-infos', + ], plugin.path), + ]), + ); }); test('allows an empty config file', () async { - createFakePlugin('foo', packagesDir, - extraFiles: ['analysis_options.yaml']); + createFakePlugin( + 'foo', + packagesDir, + extraFiles: ['analysis_options.yaml'], + ); final File allowFile = packagesDir.childFile('custom.yaml'); allowFile.createSync(); await expectLater( - () => runCapturingPrint(runner, - ['analyze', '--custom-analysis', allowFile.path]), - throwsA(isA())); + () => runCapturingPrint(runner, [ + 'analyze', + '--custom-analysis', + allowFile.path, + ]), + throwsA(isA()), + ); }); // See: https://github.com/flutter/flutter/issues/78994 test('takes an empty allow list', () async { - createFakePlugin('foo', packagesDir, - extraFiles: ['analysis_options.yaml']); + createFakePlugin( + 'foo', + packagesDir, + extraFiles: ['analysis_options.yaml'], + ); await expectLater( - () => runCapturingPrint( - runner, ['analyze', '--custom-analysis', '']), - throwsA(isA())); + () => runCapturingPrint(runner, [ + 'analyze', + '--custom-analysis', + '', + ]), + throwsA(isA()), + ); }); }); test('skips if requested if "pub get" fails in the resolver', () async { final RepositoryPackage plugin = createFakePlugin('foo', packagesDir); - final FakeProcessInfo failingPubGet = FakeProcessInfo( - MockProcess( - exitCode: 1, - stderr: 'So, because foo depends on both thing_one ^1.0.0 and ' - 'thing_two from path, version solving failed.'), - ['pub', 'get']); + final failingPubGet = FakeProcessInfo( + MockProcess( + exitCode: 1, + stderr: + 'So, because foo depends on both thing_one ^1.0.0 and ' + 'thing_two from path, version solving failed.', + ), + ['pub', 'get'], + ); processRunner.mockProcessesForExecutable['flutter'] = [ failingPubGet, // The command re-runs failures when --skip-if-resolver-fails is passed @@ -450,8 +550,10 @@ void main() { failingPubGet, ]; - final List output = await runCapturingPrint( - runner, ['analyze', '--skip-if-resolving-fails']); + final List output = await runCapturingPrint(runner, [ + 'analyze', + '--skip-if-resolving-fails', + ]); expect( output, @@ -460,32 +562,34 @@ void main() { ]), ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall('flutter', const ['pub', 'get'], plugin.path), - ProcessCall('flutter', const ['pub', 'get'], plugin.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const ['pub', 'get'], plugin.path), + ProcessCall('flutter', const ['pub', 'get'], plugin.path), + ]), + ); }); test('fails if "pub get" fails', () async { createFakePlugin('foo', packagesDir); processRunner.mockProcessesForExecutable['flutter'] = [ - FakeProcessInfo(MockProcess(exitCode: 1), ['pub', 'get']) + FakeProcessInfo(MockProcess(exitCode: 1), ['pub', 'get']), ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['analyze'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['analyze'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, - containsAllInOrder([ - contains('Unable to get dependencies'), - ]), + containsAllInOrder([contains('Unable to get dependencies')]), ); }); @@ -493,14 +597,17 @@ void main() { createFakePlugin('foo', packagesDir); processRunner.mockProcessesForExecutable['flutter'] = [ - FakeProcessInfo(MockProcess(exitCode: 1), ['pub', 'downgrade']) + FakeProcessInfo(MockProcess(exitCode: 1), ['pub', 'downgrade']), ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['analyze', '--downgrade'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['analyze', '--downgrade'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -515,14 +622,17 @@ void main() { createFakePlugin('foo', packagesDir); processRunner.mockProcessesForExecutable['dart'] = [ - FakeProcessInfo(MockProcess(exitCode: 1), ['analyze']) + FakeProcessInfo(MockProcess(exitCode: 1), ['analyze']), ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['analyze'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['analyze'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -542,8 +652,11 @@ void main() { // modify the script above, as it is run from source, but out-of-repo. // Contact stuartmorgan or devoncarew for assistance. test('Dart repo analyze command works', () async { - final RepositoryPackage plugin = createFakePlugin('foo', packagesDir, - extraFiles: ['analysis_options.yaml']); + final RepositoryPackage plugin = createFakePlugin( + 'foo', + packagesDir, + extraFiles: ['analysis_options.yaml'], + ); final File allowFile = packagesDir.childFile('custom.yaml'); allowFile.writeAsStringSync('- foo'); @@ -553,22 +666,17 @@ void main() { '--analysis-sdk', 'foo/bar/baz', '--custom-analysis', - allowFile.path + allowFile.path, ]); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - 'flutter', - const ['pub', 'get'], - plugin.path, - ), - ProcessCall( - 'foo/bar/baz/bin/dart', - const ['analyze', '--fatal-infos'], - plugin.path, - ), + ProcessCall('flutter', const ['pub', 'get'], plugin.path), + ProcessCall('foo/bar/baz/bin/dart', const [ + 'analyze', + '--fatal-infos', + ], plugin.path), ]), ); }); @@ -579,22 +687,26 @@ void main() { gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' packages/package_a/foo.dart -''')), - ]; +''', + ), + ), + ]; - final List output = - await runCapturingPrint(runner, ['analyze']); + final List output = await runCapturingPrint(runner, [ + 'analyze', + ]); expect( - output, - containsAllInOrder([ - contains('Running for package_a'), - ])); + output, + containsAllInOrder([contains('Running for package_a')]), + ); }); - const List files = [ + const files = [ 'foo.java', 'foo.kt', 'foo.m', @@ -604,30 +716,36 @@ packages/package_a/foo.dart 'foo.cpp', 'foo.h', ]; - for (final String file in files) { + for (final file in files) { test('skips command for changes to non-Dart source $file', () async { createFakePackage('package_a', packagesDir); gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: + ''' packages/package_a/$file -''')), - ]; +''', + ), + ), + ]; - final List output = - await runCapturingPrint(runner, ['analyze']); + final List output = await runCapturingPrint(runner, [ + 'analyze', + ]); expect( - output, - isNot(containsAllInOrder([ - contains('Running for package_a'), - ]))); + output, + isNot( + containsAllInOrder([contains('Running for package_a')]), + ), + ); expect( - output, - containsAllInOrder([ - contains('SKIPPING ALL PACKAGES'), - ])); + output, + containsAllInOrder([contains('SKIPPING ALL PACKAGES')]), + ); }); } @@ -636,114 +754,137 @@ packages/package_a/$file gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' README.md CODEOWNERS packages/package_a/CHANGELOG.md -''')), - ]; +''', + ), + ), + ]; - final List output = - await runCapturingPrint(runner, ['analyze']); + final List output = await runCapturingPrint(runner, [ + 'analyze', + ]); expect( - output, - isNot(containsAllInOrder([ - contains('Running for package_a'), - ]))); + output, + isNot( + containsAllInOrder([contains('Running for package_a')]), + ), + ); expect( - output, - containsAllInOrder([ - contains('SKIPPING ALL PACKAGES'), - ])); + output, + containsAllInOrder([contains('SKIPPING ALL PACKAGES')]), + ); }); }); }); group('gradle lint', () { test('runs gradle lint', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin1', packagesDir, extraFiles: [ - 'example/android/gradlew', - ], platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin1', + packagesDir, + extraFiles: ['example/android/gradlew'], + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + }, + ); - final Directory androidDir = - plugin.getExamples().first.platformDirectory(FlutterPlatform.android); + final Directory androidDir = plugin.getExamples().first.platformDirectory( + FlutterPlatform.android, + ); - final List output = await runCapturingPrint( - runner, ['analyze', '--android', '--no-dart']); + final List output = await runCapturingPrint(runner, [ + 'analyze', + '--android', + '--no-dart', + ]); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - androidDir.childFile('gradlew').path, - const ['plugin1:lintDebug'], - androidDir.path, - ), + ProcessCall(androidDir.childFile('gradlew').path, const [ + 'plugin1:lintDebug', + ], androidDir.path), ]), ); expect( - output, - containsAllInOrder([ - contains('Running for plugin1'), - contains('No issues found!'), - ])); + output, + containsAllInOrder([ + contains('Running for plugin1'), + contains('No issues found!'), + ]), + ); }); test('runs on all examples', () async { - final List examples = ['example1', 'example2']; - final RepositoryPackage plugin = createFakePlugin('plugin1', packagesDir, - examples: examples, - extraFiles: [ - 'example/example1/android/gradlew', - 'example/example2/android/gradlew', - ], - platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) - }); + final examples = ['example1', 'example2']; + final RepositoryPackage plugin = createFakePlugin( + 'plugin1', + packagesDir, + examples: examples, + extraFiles: [ + 'example/example1/android/gradlew', + 'example/example2/android/gradlew', + ], + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + }, + ); final Iterable exampleAndroidDirs = plugin.getExamples().map( - (RepositoryPackage example) => - example.platformDirectory(FlutterPlatform.android)); + (RepositoryPackage example) => + example.platformDirectory(FlutterPlatform.android), + ); - final List output = await runCapturingPrint( - runner, ['analyze', '--android', '--no-dart']); + final List output = await runCapturingPrint(runner, [ + 'analyze', + '--android', + '--no-dart', + ]); expect( processRunner.recordedCalls, orderedEquals([ for (final Directory directory in exampleAndroidDirs) - ProcessCall( - directory.childFile('gradlew').path, - const ['plugin1:lintDebug'], - directory.path, - ), + ProcessCall(directory.childFile('gradlew').path, const [ + 'plugin1:lintDebug', + ], directory.path), ]), ); expect( - output, - containsAllInOrder([ - contains('Running for plugin1'), - contains('No issues found!'), - ])); + output, + containsAllInOrder([ + contains('Running for plugin1'), + contains('No issues found!'), + ]), + ); }); test('runs --config-only build if gradlew is missing', () async { - final RepositoryPackage plugin = createFakePlugin('plugin1', packagesDir, - platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin1', + packagesDir, + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + }, + ); - final Directory androidDir = - plugin.getExamples().first.platformDirectory(FlutterPlatform.android); + final Directory androidDir = plugin.getExamples().first.platformDirectory( + FlutterPlatform.android, + ); - final List output = await runCapturingPrint( - runner, ['analyze', '--android', '--no-dart']); + final List output = await runCapturingPrint(runner, [ + 'analyze', + '--android', + '--no-dart', + ]); expect( processRunner.recordedCalls, @@ -753,58 +894,63 @@ packages/package_a/CHANGELOG.md const ['build', 'apk', '--config-only'], plugin.getExamples().first.directory.path, ), - ProcessCall( - androidDir.childFile('gradlew').path, - const ['plugin1:lintDebug'], - androidDir.path, - ), + ProcessCall(androidDir.childFile('gradlew').path, const [ + 'plugin1:lintDebug', + ], androidDir.path), ]), ); expect( - output, - containsAllInOrder([ - contains('Running for plugin1'), - contains('No issues found!'), - ])); + output, + containsAllInOrder([ + contains('Running for plugin1'), + contains('No issues found!'), + ]), + ); }); test('fails if gradlew generation fails', () async { - createFakePlugin('plugin1', packagesDir, - platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) - }); + createFakePlugin( + 'plugin1', + packagesDir, + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + }, + ); - processRunner - .mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = - [ + processRunner.mockProcessesForExecutable[getFlutterCommand( + mockPlatform, + )] = [ FakeProcessInfo(MockProcess(exitCode: 1)), ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['analyze', '--android', '--no-dart'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['analyze', '--android', '--no-dart'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder( - [ - contains('Unable to configure Gradle project'), - ], - )); + output, + containsAllInOrder([ + contains('Unable to configure Gradle project'), + ]), + ); }); test('fails if linting finds issues', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin1', packagesDir, extraFiles: [ - 'example/android/gradlew', - ], platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin1', + packagesDir, + extraFiles: ['example/android/gradlew'], + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + }, + ); final String gradlewPath = plugin .getExamples() @@ -818,80 +964,94 @@ packages/package_a/CHANGELOG.md Error? commandError; final List output = await runCapturingPrint( - runner, ['analyze', '--android', '--no-dart'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['analyze', '--android', '--no-dart'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder( - [ - contains('The following packages had errors:'), - ], - )); + output, + containsAllInOrder([ + contains('The following packages had errors:'), + ]), + ); }); test('skips non-Android plugins', () async { createFakePlugin('plugin1', packagesDir); - final List output = await runCapturingPrint( - runner, ['analyze', '--android', '--no-dart']); + final List output = await runCapturingPrint(runner, [ + 'analyze', + '--android', + '--no-dart', + ]); expect( - output, - containsAllInOrder( - [ - contains( - 'SKIPPING: Package does not contain native Android plugin code') - ], - )); + output, + containsAllInOrder([ + contains( + 'SKIPPING: Package does not contain native Android plugin code', + ), + ]), + ); }); test('skips non-inline plugins', () async { - createFakePlugin('plugin1', packagesDir, - platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.federated) - }); + createFakePlugin( + 'plugin1', + packagesDir, + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.federated), + }, + ); - final List output = await runCapturingPrint( - runner, ['analyze', '--android', '--no-dart']); + final List output = await runCapturingPrint(runner, [ + 'analyze', + '--android', + '--no-dart', + ]); expect( - output, - containsAllInOrder( - [ - contains( - 'SKIPPING: Package does not contain native Android plugin code') - ], - )); + output, + containsAllInOrder([ + contains( + 'SKIPPING: Package does not contain native Android plugin code', + ), + ]), + ); }); group('file filtering', () { - const List files = [ - 'foo.java', - 'foo.kt', - ]; - for (final String file in files) { + const files = ['foo.java', 'foo.kt']; + for (final file in files) { test('runs command for changes to $file', () async { createFakePackage('package_a', packagesDir); gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: + ''' packages/package_a/$file -''')), - ]; +''', + ), + ), + ]; - final List output = await runCapturingPrint( - runner, ['analyze', '--android', '--no-dart']); + final List output = await runCapturingPrint(runner, [ + 'analyze', + '--android', + '--no-dart', + ]); expect( - output, - containsAllInOrder([ - contains('Running for package_a'), - ])); + output, + containsAllInOrder([contains('Running for package_a')]), + ); }); } @@ -900,46 +1060,56 @@ packages/package_a/$file gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' README.md CODEOWNERS packages/package_a/CHANGELOG.md packages/package_a/lib/foo.dart -''')), - ]; +''', + ), + ), + ]; - final List output = await runCapturingPrint( - runner, ['analyze', '--android', '--no-dart']); + final List output = await runCapturingPrint(runner, [ + 'analyze', + '--android', + '--no-dart', + ]); expect( - output, - isNot(containsAllInOrder([ - contains('Running for package_a'), - ]))); + output, + isNot( + containsAllInOrder([contains('Running for package_a')]), + ), + ); expect( - output, - containsAllInOrder([ - contains('SKIPPING ALL PACKAGES'), - ])); + output, + containsAllInOrder([contains('SKIPPING ALL PACKAGES')]), + ); }); }); }); group('Xcode analyze', () { test('temporarily disables Swift Package Manager', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final RepositoryPackage example = plugin.getExamples().first; - final String originalPubspecContents = - example.pubspecFile.readAsStringSync(); + final String originalPubspecContents = example.pubspecFile + .readAsStringSync(); String? buildTimePubspecContents; processRunner.mockProcessesForExecutable['xcrun'] = [ FakeProcessInfo(MockProcess(), [], () { buildTimePubspecContents = example.pubspecFile.readAsStringSync(); - }) + }), ]; await runCapturingPrint(runner, [ @@ -949,50 +1119,69 @@ packages/package_a/lib/foo.dart ]); // Ensure that SwiftPM was disabled for the package. - expect(originalPubspecContents, - isNot(contains('enable-swift-package-manager: false'))); - expect(buildTimePubspecContents, - contains('enable-swift-package-manager: false')); + expect( + originalPubspecContents, + isNot(contains('enable-swift-package-manager: false')), + ); + expect( + buildTimePubspecContents, + contains('enable-swift-package-manager: false'), + ); // And that it was undone after. expect(example.pubspecFile.readAsStringSync(), originalPubspecContents); }); group('iOS', () { test('skip if iOS is not supported', () async { - createFakePlugin('plugin', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); - final List output = await runCapturingPrint( - runner, ['analyze', '--no-dart', '--ios']); + final List output = await runCapturingPrint(runner, [ + 'analyze', + '--no-dart', + '--ios', + ]); expect( - output, - contains( - contains('Package does not contain native iOS plugin code'))); + output, + contains(contains('Package does not contain native iOS plugin code')), + ); expect(processRunner.recordedCalls, orderedEquals([])); }); test('skip if iOS is implemented in a federated package', () async { - createFakePlugin('plugin', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.federated) - }); + createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.federated), + }, + ); - final List output = await runCapturingPrint( - runner, ['analyze', '--no-dart', '--ios']); + final List output = await runCapturingPrint(runner, [ + 'analyze', + '--no-dart', + '--ios', + ]); expect( - output, - contains( - contains('Package does not contain native iOS plugin code'))); + output, + contains(contains('Package does not contain native iOS plugin code')), + ); expect(processRunner.recordedCalls, orderedEquals([])); }); test('runs for iOS plugin', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline) - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); @@ -1003,49 +1192,48 @@ packages/package_a/lib/foo.dart ]); expect( - output, - containsAllInOrder([ - contains('Running for plugin'), - contains('plugin/example (iOS) passed analysis.') - ])); + output, + containsAllInOrder([ + contains('Running for plugin'), + contains('plugin/example (iOS) passed analysis.'), + ]), + ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'flutter', - const [ - 'build', - 'ios', - '--debug', - '--config-only', - ], - pluginExampleDirectory.path), - ProcessCall( - 'xcrun', - const [ - 'xcodebuild', - 'clean', - 'analyze', - '-workspace', - 'ios/Runner.xcworkspace', - '-scheme', - 'Runner', - '-configuration', - 'Debug', - '-destination', - 'generic/platform=iOS Simulator', - 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const [ + 'build', + 'ios', + '--debug', + '--config-only', + ], pluginExampleDirectory.path), + ProcessCall('xcrun', const [ + 'xcodebuild', + 'clean', + 'analyze', + '-workspace', + 'ios/Runner.xcworkspace', + '-scheme', + 'Runner', + '-configuration', + 'Debug', + '-destination', + 'generic/platform=iOS Simulator', + 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', + ], pluginExampleDirectory.path), + ]), + ); }); test('passes min iOS deployment version when requested', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline) - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); @@ -1053,67 +1241,62 @@ packages/package_a/lib/foo.dart 'analyze', '--no-dart', '--ios', - '--ios-min-version=14.0' + '--ios-min-version=14.0', ]); expect( - output, - containsAllInOrder([ - contains('Running for plugin'), - contains('plugin/example (iOS) passed analysis.') - ])); + output, + containsAllInOrder([ + contains('Running for plugin'), + contains('plugin/example (iOS) passed analysis.'), + ]), + ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'flutter', - const [ - 'build', - 'ios', - '--debug', - '--config-only', - ], - pluginExampleDirectory.path), - ProcessCall( - 'xcrun', - const [ - 'xcodebuild', - 'clean', - 'analyze', - '-workspace', - 'ios/Runner.xcworkspace', - '-scheme', - 'Runner', - '-configuration', - 'Debug', - '-destination', - 'generic/platform=iOS Simulator', - 'IPHONEOS_DEPLOYMENT_TARGET=14.0', - 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const [ + 'build', + 'ios', + '--debug', + '--config-only', + ], pluginExampleDirectory.path), + ProcessCall('xcrun', const [ + 'xcodebuild', + 'clean', + 'analyze', + '-workspace', + 'ios/Runner.xcworkspace', + '-scheme', + 'Runner', + '-configuration', + 'Debug', + '-destination', + 'generic/platform=iOS Simulator', + 'IPHONEOS_DEPLOYMENT_TARGET=14.0', + 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', + ], pluginExampleDirectory.path), + ]), + ); }); test('fails if xcrun fails', () async { - createFakePlugin('plugin', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline) - }); + createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); processRunner.mockProcessesForExecutable['xcrun'] = [ - FakeProcessInfo(MockProcess(exitCode: 1)) + FakeProcessInfo(MockProcess(exitCode: 1)), ]; Error? commandError; final List output = await runCapturingPrint( runner, - [ - 'analyze', - '--no-dart', - '--ios', - ], + ['analyze', '--no-dart', '--ios'], errorHandler: (Error e) { commandError = e; }, @@ -1121,50 +1304,64 @@ packages/package_a/lib/foo.dart expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('The following packages had errors:'), - contains(' plugin'), - ])); + output, + containsAllInOrder([ + contains('The following packages had errors:'), + contains(' plugin'), + ]), + ); }); }); group('macOS', () { test('skip if macOS is not supported', () async { - createFakePlugin( - 'plugin', - packagesDir, - ); + createFakePlugin('plugin', packagesDir); - final List output = await runCapturingPrint( - runner, ['analyze', '--no-dart', '--macos']); + final List output = await runCapturingPrint(runner, [ + 'analyze', + '--no-dart', + '--macos', + ]); expect( - output, - contains( - contains('Package does not contain native macOS plugin code'))); + output, + contains( + contains('Package does not contain native macOS plugin code'), + ), + ); expect(processRunner.recordedCalls, orderedEquals([])); }); test('skip if macOS is implemented in a federated package', () async { - createFakePlugin('plugin', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.federated), - }); + createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.federated), + }, + ); - final List output = await runCapturingPrint( - runner, ['analyze', '--no-dart', '--macos']); + final List output = await runCapturingPrint(runner, [ + 'analyze', + '--no-dart', + '--macos', + ]); expect( - output, - contains( - contains('Package does not contain native macOS plugin code'))); + output, + contains( + contains('Package does not contain native macOS plugin code'), + ), + ); expect(processRunner.recordedCalls, orderedEquals([])); }); test('runs for macOS plugin', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); @@ -1174,44 +1371,44 @@ packages/package_a/lib/foo.dart '--macos', ]); - expect(output, - contains(contains('plugin/example (macOS) passed analysis.'))); + expect( + output, + contains(contains('plugin/example (macOS) passed analysis.')), + ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'flutter', - const [ - 'build', - 'macos', - '--debug', - '--config-only', - ], - pluginExampleDirectory.path), - ProcessCall( - 'xcrun', - const [ - 'xcodebuild', - 'clean', - 'analyze', - '-workspace', - 'macos/Runner.xcworkspace', - '-scheme', - 'Runner', - '-configuration', - 'Debug', - 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const [ + 'build', + 'macos', + '--debug', + '--config-only', + ], pluginExampleDirectory.path), + ProcessCall('xcrun', const [ + 'xcodebuild', + 'clean', + 'analyze', + '-workspace', + 'macos/Runner.xcworkspace', + '-scheme', + 'Runner', + '-configuration', + 'Debug', + 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', + ], pluginExampleDirectory.path), + ]), + ); }); test('passes min macOS deployment version when requested', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); @@ -1219,59 +1416,61 @@ packages/package_a/lib/foo.dart 'analyze', '--no-dart', '--macos', - '--macos-min-version=12.0' + '--macos-min-version=12.0', ]); - expect(output, - contains(contains('plugin/example (macOS) passed analysis.'))); + expect( + output, + contains(contains('plugin/example (macOS) passed analysis.')), + ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'flutter', - const [ - 'build', - 'macos', - '--debug', - '--config-only', - ], - pluginExampleDirectory.path), - ProcessCall( - 'xcrun', - const [ - 'xcodebuild', - 'clean', - 'analyze', - '-workspace', - 'macos/Runner.xcworkspace', - '-scheme', - 'Runner', - '-configuration', - 'Debug', - 'MACOSX_DEPLOYMENT_TARGET=12.0', - 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const [ + 'build', + 'macos', + '--debug', + '--config-only', + ], pluginExampleDirectory.path), + ProcessCall('xcrun', const [ + 'xcodebuild', + 'clean', + 'analyze', + '-workspace', + 'macos/Runner.xcworkspace', + '-scheme', + 'Runner', + '-configuration', + 'Debug', + 'MACOSX_DEPLOYMENT_TARGET=12.0', + 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', + ], pluginExampleDirectory.path), + ]), + ); }); test('fails if xcrun fails', () async { - createFakePlugin('plugin', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); processRunner.mockProcessesForExecutable['xcrun'] = [ - FakeProcessInfo(MockProcess(exitCode: 1)) + FakeProcessInfo(MockProcess(exitCode: 1)), ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['analyze', '--no-dart', '--macos'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['analyze', '--no-dart', '--macos'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -1286,11 +1485,14 @@ packages/package_a/lib/foo.dart group('combined', () { test('runs both iOS and macOS when supported', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline), - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); @@ -1302,73 +1504,66 @@ packages/package_a/lib/foo.dart ]); expect( - output, - containsAll([ - contains('plugin/example (iOS) passed analysis.'), - contains('plugin/example (macOS) passed analysis.'), - ])); + output, + containsAll([ + contains('plugin/example (iOS) passed analysis.'), + contains('plugin/example (macOS) passed analysis.'), + ]), + ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'flutter', - const [ - 'build', - 'ios', - '--debug', - '--config-only', - ], - pluginExampleDirectory.path), - ProcessCall( - 'xcrun', - const [ - 'xcodebuild', - 'clean', - 'analyze', - '-workspace', - 'ios/Runner.xcworkspace', - '-scheme', - 'Runner', - '-configuration', - 'Debug', - '-destination', - 'generic/platform=iOS Simulator', - 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', - ], - pluginExampleDirectory.path), - ProcessCall( - 'flutter', - const [ - 'build', - 'macos', - '--debug', - '--config-only', - ], - pluginExampleDirectory.path), - ProcessCall( - 'xcrun', - const [ - 'xcodebuild', - 'clean', - 'analyze', - '-workspace', - 'macos/Runner.xcworkspace', - '-scheme', - 'Runner', - '-configuration', - 'Debug', - 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const [ + 'build', + 'ios', + '--debug', + '--config-only', + ], pluginExampleDirectory.path), + ProcessCall('xcrun', const [ + 'xcodebuild', + 'clean', + 'analyze', + '-workspace', + 'ios/Runner.xcworkspace', + '-scheme', + 'Runner', + '-configuration', + 'Debug', + '-destination', + 'generic/platform=iOS Simulator', + 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', + ], pluginExampleDirectory.path), + ProcessCall('flutter', const [ + 'build', + 'macos', + '--debug', + '--config-only', + ], pluginExampleDirectory.path), + ProcessCall('xcrun', const [ + 'xcodebuild', + 'clean', + 'analyze', + '-workspace', + 'macos/Runner.xcworkspace', + '-scheme', + 'Runner', + '-configuration', + 'Debug', + 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', + ], pluginExampleDirectory.path), + ]), + ); }); test('runs only macOS for a macOS plugin', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); @@ -1380,46 +1575,45 @@ packages/package_a/lib/foo.dart ]); expect( - output, - containsAllInOrder([ - contains('plugin/example (macOS) passed analysis.'), - ])); + output, + containsAllInOrder([ + contains('plugin/example (macOS) passed analysis.'), + ]), + ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'flutter', - const [ - 'build', - 'macos', - '--debug', - '--config-only', - ], - pluginExampleDirectory.path), - ProcessCall( - 'xcrun', - const [ - 'xcodebuild', - 'clean', - 'analyze', - '-workspace', - 'macos/Runner.xcworkspace', - '-scheme', - 'Runner', - '-configuration', - 'Debug', - 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const [ + 'build', + 'macos', + '--debug', + '--config-only', + ], pluginExampleDirectory.path), + ProcessCall('xcrun', const [ + 'xcodebuild', + 'clean', + 'analyze', + '-workspace', + 'macos/Runner.xcworkspace', + '-scheme', + 'Runner', + '-configuration', + 'Debug', + 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', + ], pluginExampleDirectory.path), + ]), + ); }); test('runs only iOS for a iOS plugin', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline) - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); @@ -1431,70 +1625,74 @@ packages/package_a/lib/foo.dart ]); expect( - output, - containsAllInOrder( - [contains('plugin/example (iOS) passed analysis.')])); + output, + containsAllInOrder([ + contains('plugin/example (iOS) passed analysis.'), + ]), + ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'flutter', - const [ - 'build', - 'ios', - '--debug', - '--config-only', - ], - pluginExampleDirectory.path), - ProcessCall( - 'xcrun', - const [ - 'xcodebuild', - 'clean', - 'analyze', - '-workspace', - 'ios/Runner.xcworkspace', - '-scheme', - 'Runner', - '-configuration', - 'Debug', - '-destination', - 'generic/platform=iOS Simulator', - 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const [ + 'build', + 'ios', + '--debug', + '--config-only', + ], pluginExampleDirectory.path), + ProcessCall('xcrun', const [ + 'xcodebuild', + 'clean', + 'analyze', + '-workspace', + 'ios/Runner.xcworkspace', + '-scheme', + 'Runner', + '-configuration', + 'Debug', + '-destination', + 'generic/platform=iOS Simulator', + 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', + ], pluginExampleDirectory.path), + ]), + ); }); }); group('file filtering', () { - const List files = [ + const files = [ 'foo.m', 'foo.swift', 'foo.cc', 'foo.cpp', 'foo.h', ]; - for (final String file in files) { + for (final file in files) { test('runs command for changes to $file', () async { createFakePackage('package_a', packagesDir); gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: + ''' packages/package_a/$file -''')), - ]; +''', + ), + ), + ]; - final List output = await runCapturingPrint( - runner, ['analyze', '--no-dart', '--ios']); + final List output = await runCapturingPrint(runner, [ + 'analyze', + '--no-dart', + '--ios', + ]); expect( - output, - containsAllInOrder([ - contains('Running for package_a'), - ])); + output, + containsAllInOrder([contains('Running for package_a')]), + ); }); } @@ -1503,29 +1701,36 @@ packages/package_a/$file gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' .gemini/config.yaml AGENTS.md README.md CODEOWNERS packages/package_a/CHANGELOG.md packages/package_a/lib/foo.dart -''')), - ]; +''', + ), + ), + ]; - final List output = await runCapturingPrint( - runner, ['analyze', '--no-dart', '--ios']); + final List output = await runCapturingPrint(runner, [ + 'analyze', + '--no-dart', + '--ios', + ]); expect( - output, - isNot(containsAllInOrder([ - contains('Running for package_a'), - ]))); + output, + isNot( + containsAllInOrder([contains('Running for package_a')]), + ), + ); expect( - output, - containsAllInOrder([ - contains('SKIPPING ALL PACKAGES'), - ])); + output, + containsAllInOrder([contains('SKIPPING ALL PACKAGES')]), + ); }); }); }); diff --git a/script/tool/test/branch_for_batch_release_command_test.dart b/script/tool/test/branch_for_batch_release_command_test.dart index ca4772036313..57ebbdfac4ee 100644 --- a/script/tool/test/branch_for_batch_release_command_test.dart +++ b/script/tool/test/branch_for_batch_release_command_test.dart @@ -21,29 +21,30 @@ void main() { late CommandRunner runner; void createPendingChangelogFile( - RepositoryPackage package, String name, String content) { - final File pendingChangelog = package.directory - .childDirectory('pending_changelogs') - .childFile(name) - ..createSync(recursive: true); + RepositoryPackage package, + String name, + String content, + ) { + final File pendingChangelog = + package.directory.childDirectory('pending_changelogs').childFile(name) + ..createSync(recursive: true); pendingChangelog.writeAsStringSync(content); } - Future> runBatchCommand( - {void Function(Error error)? errorHandler}) => - runCapturingPrint( - runner, - [ - 'branch-for-batch-release', - '--packages=a_package', - '--branch=release-branch', - '--remote=origin' - ], - errorHandler: errorHandler); + Future> runBatchCommand({ + void Function(Error error)? errorHandler, + }) => runCapturingPrint(runner, [ + 'branch-for-batch-release', + '--packages=a_package', + '--branch=release-branch', + '--remote=origin', + ], errorHandler: errorHandler); RepositoryPackage createTestPackage() { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); package.changelogFile.writeAsStringSync(''' ## 1.0.0 @@ -58,39 +59,35 @@ version: 1.0.0 return package; } - const List expectedGitCallsForABFiles = [ + const expectedGitCallsForABFiles = [ ProcessCall('git-checkout', ['-b', 'release-branch'], null), - ProcessCall( - 'git-rm', - [ - '/packages/a_package/pending_changelogs/a.yaml', - '/packages/a_package/pending_changelogs/b.yaml' - ], - null), - ProcessCall( - 'git-add', - [ - '/packages/a_package/pubspec.yaml', - '/packages/a_package/CHANGELOG.md' - ], - null), - ProcessCall('git-commit', - ['-m', '[a_package] Prepare for batch release'], null), + ProcessCall('git-rm', [ + '/packages/a_package/pending_changelogs/a.yaml', + '/packages/a_package/pending_changelogs/b.yaml', + ], null), + ProcessCall('git-add', [ + '/packages/a_package/pubspec.yaml', + '/packages/a_package/CHANGELOG.md', + ], null), + ProcessCall('git-commit', [ + '-m', + '[a_package] Prepare for batch release', + ], null), ProcessCall('git-push', ['origin', 'release-branch'], null), ]; - const List expectedGitCallsForAFiles = [ + const expectedGitCallsForAFiles = [ ProcessCall('git-checkout', ['-b', 'release-branch'], null), - ProcessCall('git-rm', - ['/packages/a_package/pending_changelogs/a.yaml'], null), - ProcessCall( - 'git-add', - [ - '/packages/a_package/pubspec.yaml', - '/packages/a_package/CHANGELOG.md' - ], - null), - ProcessCall('git-commit', - ['-m', '[a_package] Prepare for batch release'], null), + ProcessCall('git-rm', [ + '/packages/a_package/pending_changelogs/a.yaml', + ], null), + ProcessCall('git-add', [ + '/packages/a_package/pubspec.yaml', + '/packages/a_package/CHANGELOG.md', + ], null), + ProcessCall('git-commit', [ + '-m', + '[a_package] Prepare for batch release', + ], null), ProcessCall('git-push', ['origin', 'release-branch'], null), ]; @@ -99,14 +96,16 @@ version: 1.0.0 final GitDir gitDir; (:packagesDir, :processRunner, :gitProcessRunner, :gitDir) = configureBaseCommandMocks(platform: mockPlatform); - final BranchForBatchReleaseCommand command = BranchForBatchReleaseCommand( + final command = BranchForBatchReleaseCommand( packagesDir, processRunner: processRunner, gitDir: gitDir, platform: mockPlatform, ); - runner = CommandRunner('branch_for_batch_release_command', - 'Test for branch_for_batch_release_command'); + runner = CommandRunner( + 'branch_for_batch_release_command', + 'Test for branch_for_batch_release_command', + ); runner.addCommand(command); }); @@ -124,20 +123,25 @@ version: minor final List output = await runBatchCommand(); expect( - output, - containsAllInOrder([ - 'Parsing package "a_package"...', - ' Creating new branch "release-branch"...', - ' Pushing branch release-branch to remote origin...', - ])); + output, + containsAllInOrder([ + 'Parsing package "a_package"...', + ' Creating new branch "release-branch"...', + ' Pushing branch release-branch to remote origin...', + ]), + ); expect( - package.pubspecFile.readAsStringSync(), contains('version: 1.1.0')); + package.pubspecFile.readAsStringSync(), + contains('version: 1.1.0'), + ); final String changelogContent = package.changelogFile.readAsStringSync(); expect(changelogContent, startsWith('## 1.1.0')); expect(changelogContent, contains('A new feature')); - expect(gitProcessRunner.recordedCalls, - orderedEquals(expectedGitCallsForAFiles)); + expect( + gitProcessRunner.recordedCalls, + orderedEquals(expectedGitCallsForAFiles), + ); }); test('can bump major', () async { @@ -153,20 +157,25 @@ version: major final List output = await runBatchCommand(); expect( - output, - containsAllInOrder([ - 'Parsing package "a_package"...', - ' Creating new branch "release-branch"...', - ' Pushing branch release-branch to remote origin...', - ])); + output, + containsAllInOrder([ + 'Parsing package "a_package"...', + ' Creating new branch "release-branch"...', + ' Pushing branch release-branch to remote origin...', + ]), + ); expect( - package.pubspecFile.readAsStringSync(), contains('version: 2.0.0')); + package.pubspecFile.readAsStringSync(), + contains('version: 2.0.0'), + ); final String changelogContent = package.changelogFile.readAsStringSync(); expect(changelogContent, startsWith('## 2.0.0')); expect(changelogContent, contains('A new feature')); - expect(gitProcessRunner.recordedCalls, - orderedEquals(expectedGitCallsForAFiles)); + expect( + gitProcessRunner.recordedCalls, + orderedEquals(expectedGitCallsForAFiles), + ); }); test('can bump patch', () async { @@ -182,20 +191,25 @@ version: patch final List output = await runBatchCommand(); expect( - output, - containsAllInOrder([ - 'Parsing package "a_package"...', - ' Creating new branch "release-branch"...', - ' Pushing branch release-branch to remote origin...', - ])); + output, + containsAllInOrder([ + 'Parsing package "a_package"...', + ' Creating new branch "release-branch"...', + ' Pushing branch release-branch to remote origin...', + ]), + ); expect( - package.pubspecFile.readAsStringSync(), contains('version: 1.0.1')); + package.pubspecFile.readAsStringSync(), + contains('version: 1.0.1'), + ); final String changelogContent = package.changelogFile.readAsStringSync(); expect(changelogContent, startsWith('## 1.0.1')); expect(changelogContent, contains('A new feature')); - expect(gitProcessRunner.recordedCalls, - orderedEquals(expectedGitCallsForAFiles)); + expect( + gitProcessRunner.recordedCalls, + orderedEquals(expectedGitCallsForAFiles), + ); }); test('merges multiple changelogs, minor and major', () async { @@ -215,21 +229,26 @@ version: major final List output = await runBatchCommand(); expect( - output, - containsAllInOrder([ - 'Parsing package "a_package"...', - ' Creating new branch "release-branch"...', - ' Pushing branch release-branch to remote origin...', - ])); + output, + containsAllInOrder([ + 'Parsing package "a_package"...', + ' Creating new branch "release-branch"...', + ' Pushing branch release-branch to remote origin...', + ]), + ); expect( - package.pubspecFile.readAsStringSync(), contains('version: 2.0.0')); + package.pubspecFile.readAsStringSync(), + contains('version: 2.0.0'), + ); final String changelogContent = package.changelogFile.readAsStringSync(); expect(changelogContent, startsWith('## 2.0.0')); expect(changelogContent, contains('A new feature')); expect(changelogContent, contains('A breaking change')); - expect(gitProcessRunner.recordedCalls, - orderedEquals(expectedGitCallsForABFiles)); + expect( + gitProcessRunner.recordedCalls, + orderedEquals(expectedGitCallsForABFiles), + ); }); test('merges multiple changelogs, minor and patch', () async { @@ -249,21 +268,26 @@ version: patch final List output = await runBatchCommand(); expect( - output, - containsAllInOrder([ - 'Parsing package "a_package"...', - ' Creating new branch "release-branch"...', - ' Pushing branch release-branch to remote origin...', - ])); + output, + containsAllInOrder([ + 'Parsing package "a_package"...', + ' Creating new branch "release-branch"...', + ' Pushing branch release-branch to remote origin...', + ]), + ); expect( - package.pubspecFile.readAsStringSync(), contains('version: 1.1.0')); + package.pubspecFile.readAsStringSync(), + contains('version: 1.1.0'), + ); final String changelogContent = package.changelogFile.readAsStringSync(); expect(changelogContent, startsWith('## 1.1.0')); expect(changelogContent, contains('A new feature')); expect(changelogContent, contains('A bug fix')); - expect(gitProcessRunner.recordedCalls, - orderedEquals(expectedGitCallsForABFiles)); + expect( + gitProcessRunner.recordedCalls, + orderedEquals(expectedGitCallsForABFiles), + ); }); test('merges multiple changelogs, major and patch', () async { @@ -283,21 +307,26 @@ version: patch final List output = await runBatchCommand(); expect( - output, - containsAllInOrder([ - 'Parsing package "a_package"...', - ' Creating new branch "release-branch"...', - ' Pushing branch release-branch to remote origin...', - ])); + output, + containsAllInOrder([ + 'Parsing package "a_package"...', + ' Creating new branch "release-branch"...', + ' Pushing branch release-branch to remote origin...', + ]), + ); expect( - package.pubspecFile.readAsStringSync(), contains('version: 2.0.0')); + package.pubspecFile.readAsStringSync(), + contains('version: 2.0.0'), + ); final String changelogContent = package.changelogFile.readAsStringSync(); expect(changelogContent, startsWith('## 2.0.0')); expect(changelogContent, contains('A breaking change')); expect(changelogContent, contains('A bug fix')); - expect(gitProcessRunner.recordedCalls, - orderedEquals(expectedGitCallsForABFiles)); + expect( + gitProcessRunner.recordedCalls, + orderedEquals(expectedGitCallsForABFiles), + ); }); test('merges multiple changelogs, minor, major and patch', () async { @@ -321,45 +350,49 @@ version: patch final List output = await runBatchCommand(); expect( - output, - containsAllInOrder([ - 'Parsing package "a_package"...', - ' Creating new branch "release-branch"...', - ' Pushing branch release-branch to remote origin...', - ])); + output, + containsAllInOrder([ + 'Parsing package "a_package"...', + ' Creating new branch "release-branch"...', + ' Pushing branch release-branch to remote origin...', + ]), + ); expect( - package.pubspecFile.readAsStringSync(), contains('version: 2.0.0')); + package.pubspecFile.readAsStringSync(), + contains('version: 2.0.0'), + ); final String changelogContent = package.changelogFile.readAsStringSync(); expect(changelogContent, startsWith('## 2.0.0')); expect(changelogContent, contains('A new feature')); expect(changelogContent, contains('A breaking change')); expect(changelogContent, contains('A bug fix')); expect( - gitProcessRunner.recordedCalls, - orderedEquals([ - const ProcessCall( - 'git-checkout', ['-b', 'release-branch'], null), - const ProcessCall( - 'git-rm', - [ - '/packages/a_package/pending_changelogs/a.yaml', - '/packages/a_package/pending_changelogs/b.yaml', - '/packages/a_package/pending_changelogs/c.yaml' - ], - null), - const ProcessCall( - 'git-add', - [ - '/packages/a_package/pubspec.yaml', - '/packages/a_package/CHANGELOG.md' - ], - null), - const ProcessCall('git-commit', - ['-m', '[a_package] Prepare for batch release'], null), - const ProcessCall( - 'git-push', ['origin', 'release-branch'], null), - ])); + gitProcessRunner.recordedCalls, + orderedEquals([ + const ProcessCall('git-checkout', [ + '-b', + 'release-branch', + ], null), + const ProcessCall('git-rm', [ + '/packages/a_package/pending_changelogs/a.yaml', + '/packages/a_package/pending_changelogs/b.yaml', + '/packages/a_package/pending_changelogs/c.yaml', + ], null), + const ProcessCall('git-add', [ + '/packages/a_package/pubspec.yaml', + '/packages/a_package/CHANGELOG.md', + ], null), + const ProcessCall('git-commit', [ + '-m', + '[a_package] Prepare for batch release', + ], null), + const ProcessCall('git-push', [ + 'origin', + 'release-branch', + ], null), + ]), + ); }); test('merges multiple changelogs with same version', () async { @@ -379,21 +412,26 @@ version: minor final List output = await runBatchCommand(); expect( - output, - containsAllInOrder([ - 'Parsing package "a_package"...', - ' Creating new branch "release-branch"...', - ' Pushing branch release-branch to remote origin...', - ])); + output, + containsAllInOrder([ + 'Parsing package "a_package"...', + ' Creating new branch "release-branch"...', + ' Pushing branch release-branch to remote origin...', + ]), + ); expect( - package.pubspecFile.readAsStringSync(), contains('version: 1.1.0')); + package.pubspecFile.readAsStringSync(), + contains('version: 1.1.0'), + ); final String changelogContent = package.changelogFile.readAsStringSync(); expect(changelogContent, startsWith('## 1.1.0')); expect(changelogContent, contains('A new feature')); expect(changelogContent, contains('Another new feature')); - expect(gitProcessRunner.recordedCalls, - orderedEquals(expectedGitCallsForABFiles)); + expect( + gitProcessRunner.recordedCalls, + orderedEquals(expectedGitCallsForABFiles), + ); }); test('mix of skip and other version changes', () async { @@ -413,21 +451,26 @@ version: skip final List output = await runBatchCommand(); expect( - output, - containsAllInOrder([ - 'Parsing package "a_package"...', - ' Creating new branch "release-branch"...', - ' Pushing branch release-branch to remote origin...', - ])); + output, + containsAllInOrder([ + 'Parsing package "a_package"...', + ' Creating new branch "release-branch"...', + ' Pushing branch release-branch to remote origin...', + ]), + ); expect( - package.pubspecFile.readAsStringSync(), contains('version: 1.1.0')); + package.pubspecFile.readAsStringSync(), + contains('version: 1.1.0'), + ); final String changelogContent = package.changelogFile.readAsStringSync(); expect(changelogContent, startsWith('## 1.1.0')); expect(changelogContent, contains('A new feature')); expect(changelogContent, contains('A documentation update')); - expect(gitProcessRunner.recordedCalls, - orderedEquals(expectedGitCallsForABFiles)); + expect( + gitProcessRunner.recordedCalls, + orderedEquals(expectedGitCallsForABFiles), + ); }); test('skips version update', () async { @@ -443,13 +486,16 @@ version: skip final List output = await runBatchCommand(); expect( - output, - containsAllInOrder([ - 'Parsing package "a_package"...', - 'No version change specified in pending changelogs for a_package.', - ])); + output, + containsAllInOrder([ + 'Parsing package "a_package"...', + 'No version change specified in pending changelogs for a_package.', + ]), + ); expect( - package.pubspecFile.readAsStringSync(), contains('version: 1.0.0')); + package.pubspecFile.readAsStringSync(), + contains('version: 1.0.0'), + ); expect(package.changelogFile.readAsStringSync(), startsWith('## 1.0.0')); expect(gitProcessRunner.recordedCalls, orderedEquals([])); }); @@ -462,13 +508,16 @@ version: skip final List output = await runBatchCommand(); expect( - output, - containsAllInOrder([ - 'Parsing package "a_package"...', - 'No pending changelogs found for a_package.', - ])); + output, + containsAllInOrder([ + 'Parsing package "a_package"...', + 'No pending changelogs found for a_package.', + ]), + ); expect( - package.pubspecFile.readAsStringSync(), contains('version: 1.0.0')); + package.pubspecFile.readAsStringSync(), + contains('version: 1.0.0'), + ); expect(package.changelogFile.readAsStringSync(), startsWith('## 1.0.0')); expect(gitProcessRunner.recordedCalls, orderedEquals([])); }); @@ -493,11 +542,12 @@ version: minor final List output = await runBatchCommand(); expect( - output, - containsAllInOrder([ - 'Parsing package "a_package"...', - ' Creating new branch "release-branch"...', - ])); + output, + containsAllInOrder([ + 'Parsing package "a_package"...', + ' Creating new branch "release-branch"...', + ]), + ); final String changelogContent = package.changelogFile.readAsStringSync(); expect(changelogContent, ''' @@ -521,16 +571,19 @@ version: major '''); gitProcessRunner.mockProcessesForExecutable['git-checkout'] = [ - FakeProcessInfo(MockProcess(stderr: 'error', exitCode: 1)), - ]; - final List output = - await runBatchCommand(errorHandler: (Error e) { - expect(e, isA()); - expect((e as ToolExit).exitCode, 4); - }); + FakeProcessInfo(MockProcess(stderr: 'error', exitCode: 1)), + ]; + final List output = await runBatchCommand( + errorHandler: (Error e) { + expect(e, isA()); + expect((e as ToolExit).exitCode, 4); + }, + ); - expect(output.last, - contains('Failed to create branch release-branch: error')); + expect( + output.last, + contains('Failed to create branch release-branch: error'), + ); }); test('throw when git-rm fails', () async { @@ -545,16 +598,19 @@ version: major gitProcessRunner.mockProcessesForExecutable['git-rm'] = [ FakeProcessInfo(MockProcess(stderr: 'error', exitCode: 1)), ]; - final List output = - await runBatchCommand(errorHandler: (Error e) { - expect(e, isA()); - expect((e as ToolExit).exitCode, 4); - }); + final List output = await runBatchCommand( + errorHandler: (Error e) { + expect(e, isA()); + expect((e as ToolExit).exitCode, 4); + }, + ); expect( - output.last, - contains( - 'Failed to rm /packages/a_package/pending_changelogs/a.yaml: error')); + output.last, + contains( + 'Failed to rm /packages/a_package/pending_changelogs/a.yaml: error', + ), + ); }); test('throw when git-add fails', () async { @@ -568,13 +624,14 @@ version: major '''); gitProcessRunner.mockProcessesForExecutable['git-add'] = [ - FakeProcessInfo(MockProcess(stderr: 'error', exitCode: 1)), - ]; - final List output = - await runBatchCommand(errorHandler: (Error e) { - expect(e, isA()); - expect((e as ToolExit).exitCode, 4); - }); + FakeProcessInfo(MockProcess(stderr: 'error', exitCode: 1)), + ]; + final List output = await runBatchCommand( + errorHandler: (Error e) { + expect(e, isA()); + expect((e as ToolExit).exitCode, 4); + }, + ); expect(output.last, contains('Failed to git add: error')); }); @@ -590,13 +647,14 @@ version: major '''); gitProcessRunner.mockProcessesForExecutable['git-commit'] = [ - FakeProcessInfo(MockProcess(stderr: 'error', exitCode: 1)), - ]; - final List output = - await runBatchCommand(errorHandler: (Error e) { - expect(e, isA()); - expect((e as ToolExit).exitCode, 4); - }); + FakeProcessInfo(MockProcess(stderr: 'error', exitCode: 1)), + ]; + final List output = await runBatchCommand( + errorHandler: (Error e) { + expect(e, isA()); + expect((e as ToolExit).exitCode, 4); + }, + ); expect(output.last, contains('Failed to commit: error')); }); @@ -612,20 +670,23 @@ version: major '''); gitProcessRunner.mockProcessesForExecutable['git-push'] = [ - FakeProcessInfo(MockProcess(stderr: 'error', exitCode: 1)), - ]; - final List output = - await runBatchCommand(errorHandler: (Error e) { - expect(e, isA()); - expect((e as ToolExit).exitCode, 4); - }); + FakeProcessInfo(MockProcess(stderr: 'error', exitCode: 1)), + ]; + final List output = await runBatchCommand( + errorHandler: (Error e) { + expect(e, isA()); + expect((e as ToolExit).exitCode, 4); + }, + ); expect(output.last, contains('Failed to push to release-branch: error')); }); test('throws for pre-1.0.0 packages', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); addTearDown(() { package.directory.deleteSync(recursive: true); @@ -647,16 +708,19 @@ changelog: A new feature version: minor '''); - final List output = - await runBatchCommand(errorHandler: (Error e) { - expect(e, isA()); - expect((e as ToolExit).exitCode, 3); - }); + final List output = await runBatchCommand( + errorHandler: (Error e) { + expect(e, isA()); + expect((e as ToolExit).exitCode, 3); + }, + ); expect( - output.last, - contains( - 'This script only supports packages with version >= 1.0.0. Current version: 0.5.0.')); + output.last, + contains( + 'This script only supports packages with version >= 1.0.0. Current version: 0.5.0.', + ), + ); }); }); } diff --git a/script/tool/test/build_examples_command_test.dart b/script/tool/test/build_examples_command_test.dart index 8b5cb8af5482..00c1128927aa 100644 --- a/script/tool/test/build_examples_command_test.dart +++ b/script/tool/test/build_examples_command_test.dart @@ -26,7 +26,7 @@ void main() { final GitDir gitDir; (:packagesDir, :processRunner, :gitProcessRunner, :gitDir) = configureBaseCommandMocks(platform: mockPlatform); - final BuildExamplesCommand command = BuildExamplesCommand( + final command = BuildExamplesCommand( packagesDir, processRunner: processRunner, platform: mockPlatform, @@ -34,155 +34,188 @@ void main() { ); runner = CommandRunner( - 'build_examples_command', 'Test for build_example_command'); + 'build_examples_command', + 'Test for build_example_command', + ); runner.addCommand(command); }); test('fails if no plaform flags are passed', () async { Error? commandError; final List output = await runCapturingPrint( - runner, ['build-examples'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['build-examples'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('At least one platform must be provided'), - ])); + output, + containsAllInOrder([ + contains('At least one platform must be provided'), + ]), + ); }); test('fails if building fails', () async { - createFakePlugin('plugin', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline), - }); - - processRunner - .mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = - [ - FakeProcessInfo(MockProcess(exitCode: 1), ['build']) + createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); + + processRunner.mockProcessesForExecutable[getFlutterCommand( + mockPlatform, + )] = [ + FakeProcessInfo(MockProcess(exitCode: 1), ['build']), ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['build-examples', '--ios'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['build-examples', '--ios'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('The following packages had errors:'), - contains(' plugin:\n' - ' plugin/example (iOS)'), - ])); + output, + containsAllInOrder([ + contains('The following packages had errors:'), + contains( + ' plugin:\n' + ' plugin/example (iOS)', + ), + ]), + ); }); test('fails if a plugin has no examples', () async { - createFakePlugin('plugin', packagesDir, - examples: [], - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline) - }); - - processRunner - .mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = - [ - FakeProcessInfo(MockProcess(exitCode: 1), ['pub', 'get']) + createFakePlugin( + 'plugin', + packagesDir, + examples: [], + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); + + processRunner.mockProcessesForExecutable[getFlutterCommand( + mockPlatform, + )] = [ + FakeProcessInfo(MockProcess(exitCode: 1), ['pub', 'get']), ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['build-examples', '--ios'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['build-examples', '--ios'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('The following packages had errors:'), - contains(' plugin:\n' - ' No examples found'), - ])); - }); - - test('building for iOS when plugin is not set up for iOS results in no-op', - () async { - mockPlatform.isMacOS = true; - createFakePlugin('plugin', packagesDir); - - final List output = - await runCapturingPrint(runner, ['build-examples', '--ios']); - expect( output, containsAllInOrder([ - contains('Running for plugin'), - contains('iOS is not supported by this plugin'), + contains('The following packages had errors:'), + contains( + ' plugin:\n' + ' No examples found', + ), ]), ); - - // Output should be empty since running build-examples --macos with no macos - // implementation is a no-op. - expect(processRunner.recordedCalls, orderedEquals([])); }); + test( + 'building for iOS when plugin is not set up for iOS results in no-op', + () async { + mockPlatform.isMacOS = true; + createFakePlugin('plugin', packagesDir); + + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--ios', + ]); + + expect( + output, + containsAllInOrder([ + contains('Running for plugin'), + contains('iOS is not supported by this plugin'), + ]), + ); + + // Output should be empty since running build-examples --macos with no macos + // implementation is a no-op. + expect(processRunner.recordedCalls, orderedEquals([])); + }, + ); + test('building for iOS', () async { mockPlatform.isMacOS = true; - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); - final List output = await runCapturingPrint(runner, - ['build-examples', '--ios', '--enable-experiment=exp1']); + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--ios', + '--enable-experiment=exp1', + ]); expect( output, - containsAllInOrder([ - '\nBUILDING plugin/example for iOS', - ]), + containsAllInOrder(['\nBUILDING plugin/example for iOS']), ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'build', - 'ios', - '--no-codesign', - '--enable-experiment=exp1' - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'build', + 'ios', + '--no-codesign', + '--enable-experiment=exp1', + ], pluginExampleDirectory.path), + ]), + ); }); test('building for iOS with CocoaPods', () async { mockPlatform.isMacOS = true; - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final RepositoryPackage example = plugin.getExamples().first; - final String originalPubspecContents = - example.pubspecFile.readAsStringSync(); + final String originalPubspecContents = example.pubspecFile + .readAsStringSync(); String? buildTimePubspecContents; - processRunner - .mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = - [ + processRunner.mockProcessesForExecutable[getFlutterCommand( + mockPlatform, + )] = [ FakeProcessInfo(MockProcess(), ['build'], () { buildTimePubspecContents = example.pubspecFile.readAsStringSync(); - }) + }), ]; final List output = await runCapturingPrint(runner, [ @@ -194,32 +227,30 @@ void main() { expect( output, - containsAllInOrder([ - '\nBUILDING plugin/example for iOS', - ]), + containsAllInOrder(['\nBUILDING plugin/example for iOS']), ); // Ensure that SwiftPM was disabled for the package. - expect(originalPubspecContents, - isNot(contains('enable-swift-package-manager: false'))); - expect(buildTimePubspecContents, - contains('enable-swift-package-manager: false')); + expect( + originalPubspecContents, + isNot(contains('enable-swift-package-manager: false')), + ); + expect( + buildTimePubspecContents, + contains('enable-swift-package-manager: false'), + ); // And that it was undone after. expect(example.pubspecFile.readAsStringSync(), originalPubspecContents); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'build', - 'ios', - '--no-codesign', - '--enable-experiment=exp1' - ], - example.path, - ), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'build', + 'ios', + '--no-codesign', + '--enable-experiment=exp1', + ], example.path), ]), ); }); @@ -227,21 +258,24 @@ void main() { test('building for iOS with Swift Package Manager', () async { mockPlatform.isMacOS = true; - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final RepositoryPackage example = plugin.getExamples().first; - final String originalPubspecContents = - example.pubspecFile.readAsStringSync(); + final String originalPubspecContents = example.pubspecFile + .readAsStringSync(); String? buildTimePubspecContents; - processRunner - .mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = - [ + processRunner.mockProcessesForExecutable[getFlutterCommand( + mockPlatform, + )] = [ FakeProcessInfo(MockProcess(), ['build'], () { buildTimePubspecContents = example.pubspecFile.readAsStringSync(); - }) + }), ]; final List output = await runCapturingPrint(runner, [ @@ -253,92 +287,100 @@ void main() { expect( output, - containsAllInOrder([ - '\nBUILDING plugin/example for iOS', - ]), + containsAllInOrder(['\nBUILDING plugin/example for iOS']), ); // Ensure that SwiftPM was enabled for the package. - expect(originalPubspecContents, - isNot(contains('enable-swift-package-manager: true'))); - expect(buildTimePubspecContents, - contains('enable-swift-package-manager: true')); + expect( + originalPubspecContents, + isNot(contains('enable-swift-package-manager: true')), + ); + expect( + buildTimePubspecContents, + contains('enable-swift-package-manager: true'), + ); // And that it was undone after. expect(example.pubspecFile.readAsStringSync(), originalPubspecContents); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'build', - 'ios', - '--no-codesign', - '--enable-experiment=exp1' - ], - example.path, - ), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'build', + 'ios', + '--no-codesign', + '--enable-experiment=exp1', + ], example.path), ]), ); }); test( - 'building for Linux when plugin is not set up for Linux results in no-op', - () async { - mockPlatform.isLinux = true; - createFakePlugin('plugin', packagesDir); - - final List output = await runCapturingPrint( - runner, ['build-examples', '--linux']); + 'building for Linux when plugin is not set up for Linux results in no-op', + () async { + mockPlatform.isLinux = true; + createFakePlugin('plugin', packagesDir); + + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--linux', + ]); - expect( - output, - containsAllInOrder([ - contains('Running for plugin'), - contains('Linux is not supported by this plugin'), - ]), - ); + expect( + output, + containsAllInOrder([ + contains('Running for plugin'), + contains('Linux is not supported by this plugin'), + ]), + ); - // Output should be empty since running build-examples --linux with no - // Linux implementation is a no-op. - expect(processRunner.recordedCalls, orderedEquals([])); - }); + // Output should be empty since running build-examples --linux with no + // Linux implementation is a no-op. + expect(processRunner.recordedCalls, orderedEquals([])); + }, + ); test('building for Linux', () async { mockPlatform.isLinux = true; - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformLinux: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformLinux: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); - final List output = await runCapturingPrint( - runner, ['build-examples', '--linux']); + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--linux', + ]); expect( output, - containsAllInOrder([ - '\nBUILDING plugin/example for Linux', - ]), + containsAllInOrder(['\nBUILDING plugin/example for Linux']), ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall(getFlutterCommand(mockPlatform), - const ['build', 'linux'], pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'build', + 'linux', + ], pluginExampleDirectory.path), + ]), + ); }); - test('building for macOS with no implementation results in no-op', - () async { + test('building for macOS with no implementation results in no-op', () async { mockPlatform.isMacOS = true; createFakePlugin('plugin', packagesDir); - final List output = await runCapturingPrint( - runner, ['build-examples', '--macos']); + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--macos', + ]); expect( output, @@ -355,80 +397,90 @@ void main() { test('building for macOS', () async { mockPlatform.isMacOS = true; - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); - final List output = await runCapturingPrint( - runner, ['build-examples', '--macos']); + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--macos', + ]); expect( output, - containsAllInOrder([ - '\nBUILDING plugin/example for macOS', - ]), + containsAllInOrder(['\nBUILDING plugin/example for macOS']), ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall(getFlutterCommand(mockPlatform), - const ['build', 'macos'], pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'build', + 'macos', + ], pluginExampleDirectory.path), + ]), + ); }); test('building for macOS with CocoaPods', () async { mockPlatform.isMacOS = true; - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final RepositoryPackage example = plugin.getExamples().first; - final String originalPubspecContents = - example.pubspecFile.readAsStringSync(); + final String originalPubspecContents = example.pubspecFile + .readAsStringSync(); String? buildTimePubspecContents; - processRunner - .mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = - [ + processRunner.mockProcessesForExecutable[getFlutterCommand( + mockPlatform, + )] = [ FakeProcessInfo(MockProcess(), ['build'], () { buildTimePubspecContents = example.pubspecFile.readAsStringSync(); - }) + }), ]; - final List output = await runCapturingPrint(runner, - ['build-examples', '--macos', '--no-swift-package-manager']); + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--macos', + '--no-swift-package-manager', + ]); expect( output, - containsAllInOrder([ - '\nBUILDING plugin/example for macOS', - ]), + containsAllInOrder(['\nBUILDING plugin/example for macOS']), ); // Ensure that SwiftPM was enabled for the package. - expect(originalPubspecContents, - isNot(contains('enable-swift-package-manager: false'))); - expect(buildTimePubspecContents, - contains('enable-swift-package-manager: false')); + expect( + originalPubspecContents, + isNot(contains('enable-swift-package-manager: false')), + ); + expect( + buildTimePubspecContents, + contains('enable-swift-package-manager: false'), + ); // And that it was undone after. expect(example.pubspecFile.readAsStringSync(), originalPubspecContents); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'build', - 'macos', - ], - example.path, - ), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'build', + 'macos', + ], example.path), ]), ); }); @@ -436,52 +488,56 @@ void main() { test('building for macOS with Swift Package Manager', () async { mockPlatform.isMacOS = true; - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final RepositoryPackage example = plugin.getExamples().first; - final String originalPubspecContents = - example.pubspecFile.readAsStringSync(); + final String originalPubspecContents = example.pubspecFile + .readAsStringSync(); String? buildTimePubspecContents; - processRunner - .mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = - [ + processRunner.mockProcessesForExecutable[getFlutterCommand( + mockPlatform, + )] = [ FakeProcessInfo(MockProcess(), ['build'], () { buildTimePubspecContents = example.pubspecFile.readAsStringSync(); - }) + }), ]; - final List output = await runCapturingPrint(runner, - ['build-examples', '--macos', '--swift-package-manager']); + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--macos', + '--swift-package-manager', + ]); expect( output, - containsAllInOrder([ - '\nBUILDING plugin/example for macOS', - ]), + containsAllInOrder(['\nBUILDING plugin/example for macOS']), ); // Ensure that SwiftPM was enabled for the package. - expect(originalPubspecContents, - isNot(contains('enable-swift-package-manager: true'))); - expect(buildTimePubspecContents, - contains('enable-swift-package-manager: true')); + expect( + originalPubspecContents, + isNot(contains('enable-swift-package-manager: true')), + ); + expect( + buildTimePubspecContents, + contains('enable-swift-package-manager: true'), + ); // And that it was undone after. expect(example.pubspecFile.readAsStringSync(), originalPubspecContents); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'build', - 'macos', - ], - example.path, - ), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'build', + 'macos', + ], example.path), ]), ); }); @@ -489,8 +545,10 @@ void main() { test('building for web with no implementation results in no-op', () async { createFakePlugin('plugin', packagesDir); - final List output = - await runCapturingPrint(runner, ['build-examples', '--web']); + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--web', + ]); expect( output, @@ -506,108 +564,127 @@ void main() { }); test('building for web', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformWeb: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformWeb: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); - final List output = - await runCapturingPrint(runner, ['build-examples', '--web']); + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--web', + ]); expect( output, - containsAllInOrder([ - '\nBUILDING plugin/example for web', - ]), + containsAllInOrder(['\nBUILDING plugin/example for web']), ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall(getFlutterCommand(mockPlatform), - const ['build', 'web'], pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'build', + 'web', + ], pluginExampleDirectory.path), + ]), + ); }); test( - 'building for Windows when plugin is not set up for Windows results in no-op', - () async { - mockPlatform.isWindows = true; - createFakePlugin('plugin', packagesDir); - - final List output = await runCapturingPrint( - runner, ['build-examples', '--windows']); + 'building for Windows when plugin is not set up for Windows results in no-op', + () async { + mockPlatform.isWindows = true; + createFakePlugin('plugin', packagesDir); + + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--windows', + ]); - expect( - output, - containsAllInOrder([ - contains('Running for plugin'), - contains('Windows is not supported by this plugin'), - ]), - ); + expect( + output, + containsAllInOrder([ + contains('Running for plugin'), + contains('Windows is not supported by this plugin'), + ]), + ); - // Output should be empty since running build-examples --windows with no - // Windows implementation is a no-op. - expect(processRunner.recordedCalls, orderedEquals([])); - }); + // Output should be empty since running build-examples --windows with no + // Windows implementation is a no-op. + expect(processRunner.recordedCalls, orderedEquals([])); + }, + ); test('building for Windows', () async { mockPlatform.isWindows = true; - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformWindows: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformWindows: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); - final List output = await runCapturingPrint( - runner, ['build-examples', '--windows']); + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--windows', + ]); expect( output, - containsAllInOrder([ - '\nBUILDING plugin/example for Windows', - ]), + containsAllInOrder(['\nBUILDING plugin/example for Windows']), ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const ['build', 'windows'], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'build', + 'windows', + ], pluginExampleDirectory.path), + ]), + ); }); test( - 'building for Android when plugin is not set up for Android results in no-op', - () async { - createFakePlugin('plugin', packagesDir); + 'building for Android when plugin is not set up for Android results in no-op', + () async { + createFakePlugin('plugin', packagesDir); - final List output = - await runCapturingPrint(runner, ['build-examples', '--apk']); + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--apk', + ]); - expect( - output, - containsAllInOrder([ - contains('Running for plugin'), - contains('Android is not supported by this plugin'), - ]), - ); + expect( + output, + containsAllInOrder([ + contains('Running for plugin'), + contains('Android is not supported by this plugin'), + ]), + ); - // Output should be empty since running build-examples --macos with no macos - // implementation is a no-op. - expect(processRunner.recordedCalls, orderedEquals([])); - }); + // Output should be empty since running build-examples --macos with no macos + // implementation is a no-op. + expect(processRunner.recordedCalls, orderedEquals([])); + }, + ); test('building for Android', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); @@ -624,18 +701,24 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall(getFlutterCommand(mockPlatform), - const ['build', 'apk'], pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'build', + 'apk', + ], pluginExampleDirectory.path), + ]), + ); }); test('building for Android with alias', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); @@ -652,67 +735,89 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall(getFlutterCommand(mockPlatform), - const ['build', 'apk'], pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'build', + 'apk', + ], pluginExampleDirectory.path), + ]), + ); }); test('enable-experiment flag for Android', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); - await runCapturingPrint(runner, - ['build-examples', '--apk', '--enable-experiment=exp1']); + await runCapturingPrint(runner, [ + 'build-examples', + '--apk', + '--enable-experiment=exp1', + ]); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const ['build', 'apk', '--enable-experiment=exp1'], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'build', + 'apk', + '--enable-experiment=exp1', + ], pluginExampleDirectory.path), + ]), + ); }); test('enable-experiment flag for ios', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); - await runCapturingPrint(runner, - ['build-examples', '--ios', '--enable-experiment=exp1']); + await runCapturingPrint(runner, [ + 'build-examples', + '--ios', + '--enable-experiment=exp1', + ]); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'build', - 'ios', - '--no-codesign', - '--enable-experiment=exp1' - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'build', + 'ios', + '--no-codesign', + '--enable-experiment=exp1', + ], pluginExampleDirectory.path), + ]), + ); }); test('logs skipped platforms', () async { - createFakePlugin('plugin', packagesDir, - platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline), - }); + createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + }, + ); - final List output = await runCapturingPrint( - runner, ['build-examples', '--apk', '--ios', '--macos']); + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--apk', + '--ios', + '--macos', + ]); expect( output, @@ -725,12 +830,16 @@ void main() { group('packages', () { test('builds when requested platform is supported by example', () async { final RepositoryPackage package = createFakePackage( - 'package', packagesDir, isFlutter: true, extraFiles: [ - 'example/ios/Runner.xcodeproj/project.pbxproj' - ]); + 'package', + packagesDir, + isFlutter: true, + extraFiles: ['example/ios/Runner.xcodeproj/project.pbxproj'], + ); - final List output = await runCapturingPrint( - runner, ['build-examples', '--ios']); + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--ios', + ]); expect( output, @@ -741,24 +850,24 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'build', - 'ios', - '--no-codesign', - ], - getExampleDir(package).path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'build', + 'ios', + '--no-codesign', + ], getExampleDir(package).path), + ]), + ); }); test('skips non-Flutter examples', () async { createFakePackage('package', packagesDir); - final List output = await runCapturingPrint( - runner, ['build-examples', '--ios']); + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--ios', + ]); expect( output, @@ -772,11 +881,17 @@ void main() { }); test('skips when there is no example', () async { - createFakePackage('package', packagesDir, - isFlutter: true, examples: []); + createFakePackage( + 'package', + packagesDir, + isFlutter: true, + examples: [], + ); - final List output = await runCapturingPrint( - runner, ['build-examples', '--ios']); + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--ios', + ]); expect( output, @@ -790,12 +905,17 @@ void main() { }); test('skip when example does not support requested platform', () async { - createFakePackage('package', packagesDir, - isFlutter: true, - extraFiles: ['example/linux/CMakeLists.txt']); + createFakePackage( + 'package', + packagesDir, + isFlutter: true, + extraFiles: ['example/linux/CMakeLists.txt'], + ); - final List output = await runCapturingPrint( - runner, ['build-examples', '--ios']); + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--ios', + ]); expect( output, @@ -811,12 +931,17 @@ void main() { test('logs skipped platforms when only some are supported', () async { final RepositoryPackage package = createFakePackage( - 'package', packagesDir, - isFlutter: true, - extraFiles: ['example/linux/CMakeLists.txt']); + 'package', + packagesDir, + isFlutter: true, + extraFiles: ['example/linux/CMakeLists.txt'], + ); - final List output = await runCapturingPrint( - runner, ['build-examples', '--apk', '--linux']); + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--apk', + '--linux', + ]); expect( output, @@ -828,36 +953,46 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const ['build', 'linux'], - getExampleDir(package).path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'build', + 'linux', + ], getExampleDir(package).path), + ]), + ); }); }); test('The .pluginToolsConfig.yaml file', () async { mockPlatform.isLinux = true; - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformLinux: const PlatformDetails(PlatformSupport.inline), - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformLinux: const PlatformDetails(PlatformSupport.inline), + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); - final File pluginExampleConfigFile = - pluginExampleDirectory.childFile('.pluginToolsConfig.yaml'); - pluginExampleConfigFile - .writeAsStringSync('buildFlags:\n global:\n - "test argument"'); + final File pluginExampleConfigFile = pluginExampleDirectory.childFile( + '.pluginToolsConfig.yaml', + ); + pluginExampleConfigFile.writeAsStringSync( + 'buildFlags:\n global:\n - "test argument"', + ); - final List output = [ - ...await runCapturingPrint( - runner, ['build-examples', '--linux']), - ...await runCapturingPrint( - runner, ['build-examples', '--macos']), + final output = [ + ...await runCapturingPrint(runner, [ + 'build-examples', + '--linux', + ]), + ...await runCapturingPrint(runner, [ + 'build-examples', + '--macos', + ]), ]; expect( @@ -869,21 +1004,24 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const ['build', 'linux', 'test argument'], - pluginExampleDirectory.path), - ProcessCall( - getFlutterCommand(mockPlatform), - const ['build', 'macos', 'test argument'], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'build', + 'linux', + 'test argument', + ], pluginExampleDirectory.path), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'build', + 'macos', + 'test argument', + ], pluginExampleDirectory.path), + ]), + ); }); group('file filtering', () { - const List files = [ + const files = [ 'pubspec.yaml', 'foo.dart', 'foo.java', @@ -894,30 +1032,36 @@ void main() { 'foo.cpp', 'foo.h', ]; - for (final String file in files) { + for (final file in files) { test('runs command for changes to $file', () async { createFakePackage('package_a', packagesDir); gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: + ''' packages/package_a/$file -''')), - ]; +''', + ), + ), + ]; // The target platform is irrelevant here; because this repo's // packages are fully federated, there's no need to distinguish // the ignore list by target (e.g., skipping iOS tests if only Java or // Kotlin files change), because package-level filering will already // accomplish the same goal. - final List output = await runCapturingPrint( - runner, ['build-examples', '--web']); + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--web', + ]); expect( - output, - containsAllInOrder([ - contains('Running for package_a'), - ])); + output, + containsAllInOrder([contains('Running for package_a')]), + ); }); } @@ -926,26 +1070,31 @@ packages/package_a/$file gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' README.md CODEOWNERS packages/package_a/CHANGELOG.md -''')), - ]; +''', + ), + ), + ]; - final List output = - await runCapturingPrint(runner, ['build-examples']); + final List output = await runCapturingPrint(runner, [ + 'build-examples', + ]); expect( - output, - isNot(containsAllInOrder([ - contains('Running for package_a'), - ]))); + output, + isNot( + containsAllInOrder([contains('Running for package_a')]), + ), + ); expect( - output, - containsAllInOrder([ - contains('SKIPPING ALL PACKAGES'), - ])); + output, + containsAllInOrder([contains('SKIPPING ALL PACKAGES')]), + ); }); }); }); diff --git a/script/tool/test/common/file_utils_test.dart b/script/tool/test/common/file_utils_test.dart index ede305fdde0d..ac7cfeea1757 100644 --- a/script/tool/test/common/file_utils_test.dart +++ b/script/tool/test/common/file_utils_test.dart @@ -13,20 +13,28 @@ void main() { final FileSystem fileSystem = MemoryFileSystem(); final Directory base = fileSystem.directory('/').childDirectory('base'); - final File file = - childFileWithSubcomponents(base, ['foo', 'bar', 'baz.txt']); + final File file = childFileWithSubcomponents(base, [ + 'foo', + 'bar', + 'baz.txt', + ]); expect(file.absolute.path, '/base/foo/bar/baz.txt'); }); test('works on Windows', () async { - final FileSystem fileSystem = - MemoryFileSystem(style: FileSystemStyle.windows); + final FileSystem fileSystem = MemoryFileSystem( + style: FileSystemStyle.windows, + ); - final Directory base = - fileSystem.directory(r'C:\').childDirectory('base'); - final File file = - childFileWithSubcomponents(base, ['foo', 'bar', 'baz.txt']); + final Directory base = fileSystem + .directory(r'C:\') + .childDirectory('base'); + final File file = childFileWithSubcomponents(base, [ + 'foo', + 'bar', + 'baz.txt', + ]); expect(file.absolute.path, r'C:\base\foo\bar\baz.txt'); }); @@ -37,20 +45,28 @@ void main() { final FileSystem fileSystem = MemoryFileSystem(); final Directory base = fileSystem.directory('/').childDirectory('base'); - final Directory dir = - childDirectoryWithSubcomponents(base, ['foo', 'bar', 'baz']); + final Directory dir = childDirectoryWithSubcomponents(base, [ + 'foo', + 'bar', + 'baz', + ]); expect(dir.absolute.path, '/base/foo/bar/baz'); }); test('works on Windows', () async { - final FileSystem fileSystem = - MemoryFileSystem(style: FileSystemStyle.windows); + final FileSystem fileSystem = MemoryFileSystem( + style: FileSystemStyle.windows, + ); - final Directory base = - fileSystem.directory(r'C:\').childDirectory('base'); - final Directory dir = - childDirectoryWithSubcomponents(base, ['foo', 'bar', 'baz']); + final Directory base = fileSystem + .directory(r'C:\') + .childDirectory('base'); + final Directory dir = childDirectoryWithSubcomponents(base, [ + 'foo', + 'bar', + 'baz', + ]); expect(dir.absolute.path, r'C:\base\foo\bar\baz'); }); diff --git a/script/tool/test/common/git_version_finder_test.dart b/script/tool/test/common/git_version_finder_test.dart index 349128204380..c4d3b641b399 100644 --- a/script/tool/test/common/git_version_finder_test.dart +++ b/script/tool/test/common/git_version_finder_test.dart @@ -14,16 +14,16 @@ void main() { late List?> gitDirCommands; late String gitDiffResponse; late MockGitDir gitDir; - String mergeBaseResponse = ''; + var mergeBaseResponse = ''; setUp(() { gitDirCommands = ?>[]; gitDiffResponse = ''; gitDir = MockGitDir(); - when(gitDir.runCommand(any, throwOnError: anyNamed('throwOnError'))) - .thenAnswer((Invocation invocation) { - final List arguments = - invocation.positionalArguments[0]! as List; + when( + gitDir.runCommand(any, throwOnError: anyNamed('throwOnError')), + ).thenAnswer((Invocation invocation) { + final arguments = invocation.positionalArguments[0]! as List; gitDirCommands.add(arguments); String? gitStdOut; if (arguments[0] == 'diff') { @@ -32,13 +32,13 @@ void main() { gitStdOut = mergeBaseResponse; } return Future.value( - ProcessResult(0, 0, gitStdOut ?? '', '')); + ProcessResult(0, 0, gitStdOut ?? '', ''), + ); }); }); test('No git diff should result no files changed', () async { - final GitVersionFinder finder = - GitVersionFinder(gitDir, baseSha: 'some base sha'); + final finder = GitVersionFinder(gitDir, baseSha: 'some base sha'); final List changedFiles = await finder.getChangedFiles(); expect(changedFiles, isEmpty); @@ -49,8 +49,7 @@ void main() { file1/file1.cc file2/file2.cc '''; - final GitVersionFinder finder = - GitVersionFinder(gitDir, baseSha: 'some base sha'); + final finder = GitVersionFinder(gitDir, baseSha: 'some base sha'); final List changedFiles = await finder.getChangedFiles(); expect(changedFiles, equals(['file1/file1.cc', 'file2/file2.cc'])); @@ -63,13 +62,24 @@ file1/pubspec.yaml file2/file2.cc '''; - final GitVersionFinder finder = GitVersionFinder(gitDir); + final finder = GitVersionFinder(gitDir); await finder.getChangedFiles(); - verify(gitDir.runCommand( - ['merge-base', '--fork-point', 'main', 'HEAD'], - throwOnError: false)); - verify(gitDir.runCommand( - ['diff', '--name-only', mergeBaseResponse, 'HEAD'])); + verify( + gitDir.runCommand([ + 'merge-base', + '--fork-point', + 'main', + 'HEAD', + ], throwOnError: false), + ); + verify( + gitDir.runCommand([ + 'diff', + '--name-only', + mergeBaseResponse, + 'HEAD', + ]), + ); }); test('uses correct base branch to find base sha if specified', () async { @@ -79,37 +89,46 @@ file1/pubspec.yaml file2/file2.cc '''; - final GitVersionFinder finder = - GitVersionFinder(gitDir, baseBranch: 'upstream/main'); + final finder = GitVersionFinder(gitDir, baseBranch: 'upstream/main'); await finder.getChangedFiles(); - verify(gitDir.runCommand( - ['merge-base', '--fork-point', 'upstream/main', 'HEAD'], - throwOnError: false)); - verify(gitDir.runCommand( - ['diff', '--name-only', mergeBaseResponse, 'HEAD'])); + verify( + gitDir.runCommand([ + 'merge-base', + '--fork-point', + 'upstream/main', + 'HEAD', + ], throwOnError: false), + ); + verify( + gitDir.runCommand([ + 'diff', + '--name-only', + mergeBaseResponse, + 'HEAD', + ]), + ); }); test('use correct base sha if specified', () async { - const String customBaseSha = 'aklsjdcaskf12312'; + const customBaseSha = 'aklsjdcaskf12312'; gitDiffResponse = ''' file1/pubspec.yaml file2/file2.cc '''; - final GitVersionFinder finder = - GitVersionFinder(gitDir, baseSha: customBaseSha); + final finder = GitVersionFinder(gitDir, baseSha: customBaseSha); await finder.getChangedFiles(); - verify(gitDir - .runCommand(['diff', '--name-only', customBaseSha, 'HEAD'])); + verify( + gitDir.runCommand(['diff', '--name-only', customBaseSha, 'HEAD']), + ); }); test('include uncommitted files if requested', () async { - const String customBaseSha = 'aklsjdcaskf12312'; + const customBaseSha = 'aklsjdcaskf12312'; gitDiffResponse = ''' file1/pubspec.yaml file2/file2.cc '''; - final GitVersionFinder finder = - GitVersionFinder(gitDir, baseSha: customBaseSha); + final finder = GitVersionFinder(gitDir, baseSha: customBaseSha); await finder.getChangedFiles(includeUncommitted: true); // The call should not have HEAD as a final argument like the default diff. verify(gitDir.runCommand(['diff', '--name-only', customBaseSha])); diff --git a/script/tool/test/common/gradle_test.dart b/script/tool/test/common/gradle_test.dart index 4e2cc9566e15..6422d02ccc66 100644 --- a/script/tool/test/common/gradle_test.dart +++ b/script/tool/test/common/gradle_test.dart @@ -20,9 +20,12 @@ void main() { group('isConfigured', () { test('reports true when configured on Windows', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - extraFiles: ['android/gradlew.bat']); - final GradleProject project = GradleProject( + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: ['android/gradlew.bat'], + ); + final project = GradleProject( plugin, processRunner: processRunner, platform: MockPlatform(isWindows: true), @@ -32,9 +35,12 @@ void main() { }); test('reports true when configured on non-Windows', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - extraFiles: ['android/gradlew']); - final GradleProject project = GradleProject( + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: ['android/gradlew'], + ); + final project = GradleProject( plugin, processRunner: processRunner, platform: MockPlatform(isMacOS: true), @@ -44,9 +50,12 @@ void main() { }); test('reports false when not configured on Windows', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - extraFiles: ['android/foo']); - final GradleProject project = GradleProject( + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: ['android/foo'], + ); + final project = GradleProject( plugin, processRunner: processRunner, platform: MockPlatform(isWindows: true), @@ -56,9 +65,12 @@ void main() { }); test('reports true when configured on non-Windows', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - extraFiles: ['android/foo']); - final GradleProject project = GradleProject( + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: ['android/foo'], + ); + final project = GradleProject( plugin, processRunner: processRunner, platform: MockPlatform(isMacOS: true), @@ -70,9 +82,12 @@ void main() { group('runCommand', () { test('runs without arguments', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - extraFiles: ['android/gradlew']); - final GradleProject project = GradleProject( + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: ['android/gradlew'], + ); + final project = GradleProject( plugin, processRunner: processRunner, platform: MockPlatform(isMacOS: true), @@ -82,24 +97,27 @@ void main() { expect(exitCode, 0); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - plugin - .platformDirectory(FlutterPlatform.android) - .childFile('gradlew') - .path, - const [ - 'foo', - ], - plugin.platformDirectory(FlutterPlatform.android).path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + plugin + .platformDirectory(FlutterPlatform.android) + .childFile('gradlew') + .path, + const ['foo'], + plugin.platformDirectory(FlutterPlatform.android).path, + ), + ]), + ); }); test('runs with arguments', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - extraFiles: ['android/gradlew']); - final GradleProject project = GradleProject( + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: ['android/gradlew'], + ); + final project = GradleProject( plugin, processRunner: processRunner, platform: MockPlatform(isMacOS: true), @@ -112,26 +130,27 @@ void main() { expect(exitCode, 0); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - plugin - .platformDirectory(FlutterPlatform.android) - .childFile('gradlew') - .path, - const [ - 'foo', - '--bar', - '--baz', - ], - plugin.platformDirectory(FlutterPlatform.android).path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + plugin + .platformDirectory(FlutterPlatform.android) + .childFile('gradlew') + .path, + const ['foo', '--bar', '--baz'], + plugin.platformDirectory(FlutterPlatform.android).path, + ), + ]), + ); }); test('runs with the correct wrapper on Windows', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - extraFiles: ['android/gradlew.bat']); - final GradleProject project = GradleProject( + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: ['android/gradlew.bat'], + ); + final project = GradleProject( plugin, processRunner: processRunner, platform: MockPlatform(isWindows: true), @@ -141,33 +160,34 @@ void main() { expect(exitCode, 0); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - plugin - .platformDirectory(FlutterPlatform.android) - .childFile('gradlew.bat') - .path, - const [ - 'foo', - ], - plugin.platformDirectory(FlutterPlatform.android).path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + plugin + .platformDirectory(FlutterPlatform.android) + .childFile('gradlew.bat') + .path, + const ['foo'], + plugin.platformDirectory(FlutterPlatform.android).path, + ), + ]), + ); }); test('returns error codes', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - extraFiles: ['android/gradlew.bat']); - final GradleProject project = GradleProject( + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: ['android/gradlew.bat'], + ); + final project = GradleProject( plugin, processRunner: processRunner, platform: MockPlatform(isWindows: true), ); processRunner.mockProcessesForExecutable[project.gradleWrapper.path] = - [ - FakeProcessInfo(MockProcess(exitCode: 1)), - ]; + [FakeProcessInfo(MockProcess(exitCode: 1))]; final int exitCode = await project.runCommand('foo'); diff --git a/script/tool/test/common/output_utils_test.dart b/script/tool/test/common/output_utils_test.dart index 8eb9fec0be2d..7a09807bde13 100644 --- a/script/tool/test/common/output_utils_test.dart +++ b/script/tool/test/common/output_utils_test.dart @@ -19,31 +19,39 @@ void main() { }); test('colorize works', () async { - const String message = 'a message'; + const message = 'a message'; expect( - colorizeString(message, Styles.MAGENTA), '\x1B[35m$message\x1B[0m'); + colorizeString(message, Styles.MAGENTA), + '\x1B[35m$message\x1B[0m', + ); }); test('printSuccess is green', () async { - const String message = 'a message'; + const message = 'a message'; - expect(await _capturePrint(() => printSuccess(message)), - '\x1B[32m$message\x1B[0m'); + expect( + await _capturePrint(() => printSuccess(message)), + '\x1B[32m$message\x1B[0m', + ); }); test('printWarning is yellow', () async { - const String message = 'a message'; + const message = 'a message'; - expect(await _capturePrint(() => printWarning(message)), - '\x1B[33m$message\x1B[0m'); + expect( + await _capturePrint(() => printWarning(message)), + '\x1B[33m$message\x1B[0m', + ); }); test('printError is red', () async { - const String message = 'a message'; + const message = 'a message'; - expect(await _capturePrint(() => printError(message)), - '\x1B[31m$message\x1B[0m'); + expect( + await _capturePrint(() => printError(message)), + '\x1B[31m$message\x1B[0m', + ); }); }); @@ -57,25 +65,25 @@ void main() { }); test('colorize no-ops', () async { - const String message = 'a message'; + const message = 'a message'; expect(colorizeString(message, Styles.MAGENTA), message); }); test('printSuccess just prints', () async { - const String message = 'a message'; + const message = 'a message'; expect(await _capturePrint(() => printSuccess(message)), message); }); test('printWarning just prints', () async { - const String message = 'a message'; + const message = 'a message'; expect(await _capturePrint(() => printWarning(message)), message); }); test('printError just prints', () async { - const String message = 'a message'; + const message = 'a message'; expect(await _capturePrint(() => printError(message)), message); }); @@ -86,8 +94,8 @@ void main() { /// what was printed. /// A custom [errorHandler] can be used to handle the runner error as desired without throwing. Future _capturePrint(void Function() printFunction) async { - final StringBuffer output = StringBuffer(); - final ZoneSpecification spec = ZoneSpecification( + final output = StringBuffer(); + final spec = ZoneSpecification( print: (_, __, ___, String message) { output.write(message); }, diff --git a/script/tool/test/common/package_command_test.dart b/script/tool/test/common/package_command_test.dart index 94903d03d9ac..24634d362282 100644 --- a/script/tool/test/common/package_command_test.dart +++ b/script/tool/test/common/package_command_test.dart @@ -25,7 +25,7 @@ void main() { late Directory thirdPartyPackagesDir; SamplePackageCommand configureCommand({bool includeSubpackages = false}) { - final SamplePackageCommand command = SamplePackageCommand( + final command = SamplePackageCommand( packagesDir, processRunner: processRunner, platform: mockPlatform, @@ -44,109 +44,142 @@ void main() { .childDirectory('packages'); command = configureCommand(); - runner = - CommandRunner('common_command', 'Test for common functionality'); + runner = CommandRunner( + 'common_command', + 'Test for common functionality', + ); runner.addCommand(command); }); group('plugin iteration', () { test('all plugins from file system', () async { - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); - final RepositoryPackage plugin2 = - createFakePlugin('plugin2', packagesDir); + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir, + ); await runCapturingPrint(runner, ['sample']); - expect(command.plugins, - unorderedEquals([plugin1.path, plugin2.path])); + expect( + command.plugins, + unorderedEquals([plugin1.path, plugin2.path]), + ); }); test('includes both plugins and packages', () async { - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); - final RepositoryPackage plugin2 = - createFakePlugin('plugin2', packagesDir); - final RepositoryPackage package3 = - createFakePackage('package3', packagesDir); - final RepositoryPackage package4 = - createFakePackage('package4', packagesDir); + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir, + ); + final RepositoryPackage package3 = createFakePackage( + 'package3', + packagesDir, + ); + final RepositoryPackage package4 = createFakePackage( + 'package4', + packagesDir, + ); await runCapturingPrint(runner, ['sample']); expect( - command.plugins, - unorderedEquals([ - plugin1.path, - plugin2.path, - package3.path, - package4.path, - ])); + command.plugins, + unorderedEquals([ + plugin1.path, + plugin2.path, + package3.path, + package4.path, + ]), + ); }); test('includes packages without source', () async { - final RepositoryPackage package = - createFakePackage('package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'package', + packagesDir, + ); package.libDirectory.deleteSync(recursive: true); await runCapturingPrint(runner, ['sample']); - expect( - command.plugins, - unorderedEquals([ - package.path, - ])); + expect(command.plugins, unorderedEquals([package.path])); }); test('all plugins includes third_party/packages', () async { - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); - final RepositoryPackage plugin2 = - createFakePlugin('plugin2', packagesDir); - final RepositoryPackage plugin3 = - createFakePlugin('plugin3', thirdPartyPackagesDir); + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir, + ); + final RepositoryPackage plugin3 = createFakePlugin( + 'plugin3', + thirdPartyPackagesDir, + ); await runCapturingPrint(runner, ['sample']); - expect(command.plugins, - unorderedEquals([plugin1.path, plugin2.path, plugin3.path])); + expect( + command.plugins, + unorderedEquals([plugin1.path, plugin2.path, plugin3.path]), + ); }); test('--packages limits packages', () async { - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); createFakePlugin('plugin2', packagesDir); createFakePackage('package3', packagesDir); - final RepositoryPackage package4 = - createFakePackage('package4', packagesDir); - await runCapturingPrint( - runner, ['sample', '--packages=plugin1,package4']); + final RepositoryPackage package4 = createFakePackage( + 'package4', + packagesDir, + ); + await runCapturingPrint(runner, [ + 'sample', + '--packages=plugin1,package4', + ]); expect( - command.plugins, - unorderedEquals([ - plugin1.path, - package4.path, - ])); + command.plugins, + unorderedEquals([plugin1.path, package4.path]), + ); }); test('--plugins acts as an alias to --packages', () async { - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); createFakePlugin('plugin2', packagesDir); createFakePackage('package3', packagesDir); - final RepositoryPackage package4 = - createFakePackage('package4', packagesDir); - await runCapturingPrint( - runner, ['sample', '--plugins=plugin1,package4']); + final RepositoryPackage package4 = createFakePackage( + 'package4', + packagesDir, + ); + await runCapturingPrint(runner, [ + 'sample', + '--plugins=plugin1,package4', + ]); expect( - command.plugins, - unorderedEquals([ - plugin1.path, - package4.path, - ])); + command.plugins, + unorderedEquals([plugin1.path, package4.path]), + ); }); test('exclude packages when packages flag is specified', () async { createFakePlugin('plugin1', packagesDir); - final RepositoryPackage plugin2 = - createFakePlugin('plugin2', packagesDir); + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir, + ); await runCapturingPrint(runner, [ 'sample', '--packages=plugin1,plugin2', - '--exclude=plugin1' + '--exclude=plugin1', ]); expect(command.plugins, unorderedEquals([plugin2.path])); }); @@ -154,36 +187,44 @@ void main() { test("exclude packages when packages flag isn't specified", () async { createFakePlugin('plugin1', packagesDir); createFakePlugin('plugin2', packagesDir); - await runCapturingPrint( - runner, ['sample', '--exclude=plugin1,plugin2']); - expect(command.plugins, unorderedEquals([])); - }); - - test('exclude federated plugins when packages flag is specified', () async { - createFakePlugin('plugin1', packagesDir.childDirectory('federated')); - final RepositoryPackage plugin2 = - createFakePlugin('plugin2', packagesDir); await runCapturingPrint(runner, [ 'sample', - '--packages=federated/plugin1,plugin2', - '--exclude=federated/plugin1' + '--exclude=plugin1,plugin2', ]); - expect(command.plugins, unorderedEquals([plugin2.path])); + expect(command.plugins, unorderedEquals([])); }); - test('exclude entire federated plugins when packages flag is specified', - () async { + test('exclude federated plugins when packages flag is specified', () async { createFakePlugin('plugin1', packagesDir.childDirectory('federated')); - final RepositoryPackage plugin2 = - createFakePlugin('plugin2', packagesDir); + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir, + ); await runCapturingPrint(runner, [ 'sample', '--packages=federated/plugin1,plugin2', - '--exclude=federated' + '--exclude=federated/plugin1', ]); expect(command.plugins, unorderedEquals([plugin2.path])); }); + test( + 'exclude entire federated plugins when packages flag is specified', + () async { + createFakePlugin('plugin1', packagesDir.childDirectory('federated')); + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir, + ); + await runCapturingPrint(runner, [ + 'sample', + '--packages=federated/plugin1,plugin2', + '--exclude=federated', + ]); + expect(command.plugins, unorderedEquals([plugin2.path])); + }, + ); + test('exclude accepts config files', () async { createFakePlugin('plugin1', packagesDir); final File configFile = packagesDir.childFile('exclude.yaml'); @@ -192,14 +233,16 @@ void main() { await runCapturingPrint(runner, [ 'sample', '--packages=plugin1', - '--exclude=${configFile.path}' + '--exclude=${configFile.path}', ]); expect(command.plugins, unorderedEquals([])); }); test('exclude accepts empty config files', () async { - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); final File configFile1 = packagesDir.childFile('exclude1.yaml'); configFile1.createSync(); final File configFile2 = packagesDir.childFile('exclude2.yaml'); @@ -216,8 +259,10 @@ void main() { }); test('filter-packages-to accepts config files', () async { - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); createFakePlugin('plugin2', packagesDir); final File configFile = packagesDir.childFile('exclude.yaml'); configFile.writeAsStringSync('- plugin1'); @@ -225,189 +270,228 @@ void main() { await runCapturingPrint(runner, [ 'sample', '--packages=plugin1,plugin2', - '--filter-packages-to=${configFile.path}' + '--filter-packages-to=${configFile.path}', ]); expect(command.plugins, unorderedEquals([plugin1.path])); }); - test( - 'explicitly specifying the plugin (group) name of a federated plugin ' + test('explicitly specifying the plugin (group) name of a federated plugin ' 'should include all plugins in the group', () async { final Directory pluginGroup = packagesDir.childDirectory('plugin1'); - final RepositoryPackage appFacingPackage = - createFakePlugin('plugin1', pluginGroup); - final RepositoryPackage platformInterfacePackage = - createFakePlugin('plugin1_platform_interface', pluginGroup); - final RepositoryPackage implementationPackage = - createFakePlugin('plugin1_web', pluginGroup); + final RepositoryPackage appFacingPackage = createFakePlugin( + 'plugin1', + pluginGroup, + ); + final RepositoryPackage platformInterfacePackage = createFakePlugin( + 'plugin1_platform_interface', + pluginGroup, + ); + final RepositoryPackage implementationPackage = createFakePlugin( + 'plugin1_web', + pluginGroup, + ); await runCapturingPrint(runner, ['sample', '--packages=plugin1']); expect( - command.plugins, - unorderedEquals([ - appFacingPackage.path, - platformInterfacePackage.path, - implementationPackage.path - ])); + command.plugins, + unorderedEquals([ + appFacingPackage.path, + platformInterfacePackage.path, + implementationPackage.path, + ]), + ); }); - test( - 'specifying the app-facing package of a federated plugin with ' + test('specifying the app-facing package of a federated plugin with ' '--exact-match-only should only include only that package', () async { final Directory pluginGroup = packagesDir.childDirectory('plugin1'); - final RepositoryPackage appFacingPackage = - createFakePlugin('plugin1', pluginGroup); + final RepositoryPackage appFacingPackage = createFakePlugin( + 'plugin1', + pluginGroup, + ); createFakePlugin('plugin1_platform_interface', pluginGroup); createFakePlugin('plugin1_web', pluginGroup); - await runCapturingPrint(runner, - ['sample', '--packages=plugin1', '--exact-match-only']); + await runCapturingPrint(runner, [ + 'sample', + '--packages=plugin1', + '--exact-match-only', + ]); expect(command.plugins, unorderedEquals([appFacingPackage.path])); }); - test( - 'specifying the app-facing package of a federated plugin using its ' + test('specifying the app-facing package of a federated plugin using its ' 'fully qualified name should include only that package', () async { gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin1/plugin1/plugin1.dart -''')), - ]; +''', + ), + ), + ]; final Directory pluginGroup = packagesDir.childDirectory('plugin1'); - final RepositoryPackage appFacingPackage = - createFakePlugin('plugin1', pluginGroup); + final RepositoryPackage appFacingPackage = createFakePlugin( + 'plugin1', + pluginGroup, + ); createFakePlugin('plugin1_platform_interface', pluginGroup); createFakePlugin('plugin1_web', pluginGroup); - await runCapturingPrint(runner, - ['sample', '--base-sha=main', '--packages=plugin1/plugin1']); + await runCapturingPrint(runner, [ + 'sample', + '--base-sha=main', + '--packages=plugin1/plugin1', + ]); expect(command.plugins, unorderedEquals([appFacingPackage.path])); }); - test( - 'specifying a package of a federated plugin by its name should ' + test('specifying a package of a federated plugin by its name should ' 'include only that package', () async { gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin1/plugin1/plugin1.dart -''')), - ]; +''', + ), + ), + ]; final Directory pluginGroup = packagesDir.childDirectory('plugin1'); createFakePlugin('plugin1', pluginGroup); - final RepositoryPackage platformInterfacePackage = - createFakePlugin('plugin1_platform_interface', pluginGroup); + final RepositoryPackage platformInterfacePackage = createFakePlugin( + 'plugin1_platform_interface', + pluginGroup, + ); createFakePlugin('plugin1_web', pluginGroup); await runCapturingPrint(runner, [ 'sample', '--base-sha=main', - '--packages=plugin1_platform_interface' + '--packages=plugin1_platform_interface', ]); - expect(command.plugins, - unorderedEquals([platformInterfacePackage.path])); + expect( + command.plugins, + unorderedEquals([platformInterfacePackage.path]), + ); }); test('returns subpackages after the enclosing package', () async { - final SamplePackageCommand localCommand = - configureCommand(includeSubpackages: true); - final CommandRunner localRunner = - CommandRunner('common_command', 'subpackage testing'); + final SamplePackageCommand localCommand = configureCommand( + includeSubpackages: true, + ); + final localRunner = CommandRunner( + 'common_command', + 'subpackage testing', + ); localRunner.addCommand(localCommand); - final RepositoryPackage package = - createFakePackage('apackage', packagesDir); + final RepositoryPackage package = createFakePackage( + 'apackage', + packagesDir, + ); await runCapturingPrint(localRunner, ['sample']); expect( - localCommand.plugins, - containsAllInOrder([ - package.path, - getExampleDir(package).path, - ])); + localCommand.plugins, + containsAllInOrder([package.path, getExampleDir(package).path]), + ); }); group('conflicting package selection', () { - test('does not allow --packages with --run-on-changed-packages', - () async { - Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'sample', - '--run-on-changed-packages', - '--packages=plugin1', - ], errorHandler: (Error e) { - commandError = e; - }); - - expect(commandError, isA()); - expect( + test( + 'does not allow --packages with --run-on-changed-packages', + () async { + Error? commandError; + final List output = await runCapturingPrint( + runner, + [ + 'sample', + '--run-on-changed-packages', + '--packages=plugin1', + ], + errorHandler: (Error e) { + commandError = e; + }, + ); + + expect(commandError, isA()); + expect( output, containsAllInOrder([ - contains('Only one of the package selection arguments') - ])); - }); + contains('Only one of the package selection arguments'), + ]), + ); + }, + ); test('does not allow --packages with --packages-for-branch', () async { Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'sample', - '--packages-for-branch', - '--packages=plugin1', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['sample', '--packages-for-branch', '--packages=plugin1'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Only one of the package selection arguments') - ])); + output, + containsAllInOrder([ + contains('Only one of the package selection arguments'), + ]), + ); }); test('does not allow --packages with --current-package', () async { Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'sample', - '--current-package', - '--packages=plugin1', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['sample', '--current-package', '--packages=plugin1'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Only one of the package selection arguments') - ])); + output, + containsAllInOrder([ + contains('Only one of the package selection arguments'), + ]), + ); }); test( - 'does not allow --run-on-changed-packages with --packages-for-branch', - () async { - Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'sample', - '--packages-for-branch', - '--packages=plugin1', - ], errorHandler: (Error e) { - commandError = e; - }); - - expect(commandError, isA()); - expect( + 'does not allow --run-on-changed-packages with --packages-for-branch', + () async { + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['sample', '--packages-for-branch', '--packages=plugin1'], + errorHandler: (Error e) { + commandError = e; + }, + ); + + expect(commandError, isA()); + expect( output, containsAllInOrder([ - contains('Only one of the package selection arguments') - ])); - }); + contains('Only one of the package selection arguments'), + ]), + ); + }, + ); }); group('current-package', () { @@ -415,394 +499,605 @@ packages/plugin1/plugin1/plugin1.dart packagesDir.fileSystem.currentDirectory = packagesDir.parent; Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'sample', - '--current-package', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['sample', '--current-package'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('--current-package can only be used within a repository ' - 'package or package group') - ])); + output, + containsAllInOrder([ + contains( + '--current-package can only be used within a repository ' + 'package or package group', + ), + ]), + ); }); test('throws when run directly in the packages directory', () async { packagesDir.fileSystem.currentDirectory = packagesDir; Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'sample', - '--current-package', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['sample', '--current-package'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('--current-package can only be used within a repository ' - 'package or package group') - ])); + output, + containsAllInOrder([ + contains( + '--current-package can only be used within a repository ' + 'package or package group', + ), + ]), + ); }); test('runs on a package when run from the package directory', () async { - final RepositoryPackage package = - createFakePlugin('a_package', packagesDir); + final RepositoryPackage package = createFakePlugin( + 'a_package', + packagesDir, + ); createFakePlugin('another_package', packagesDir); packagesDir.fileSystem.currentDirectory = package.directory; - await runCapturingPrint( - runner, ['sample', '--current-package']); + await runCapturingPrint(runner, [ + 'sample', + '--current-package', + ]); expect(command.plugins, unorderedEquals([package.path])); }); - test('runs on a package when run from the third_party/packages directory', - () async { - final RepositoryPackage package = - createFakePlugin('a_package', thirdPartyPackagesDir); - createFakePlugin('another_package', thirdPartyPackagesDir); - packagesDir.fileSystem.currentDirectory = package.directory; - - await runCapturingPrint( - runner, ['sample', '--current-package']); - - expect(command.plugins, unorderedEquals([package.path])); - }); + test( + 'runs on a package when run from the third_party/packages directory', + () async { + final RepositoryPackage package = createFakePlugin( + 'a_package', + thirdPartyPackagesDir, + ); + createFakePlugin('another_package', thirdPartyPackagesDir); + packagesDir.fileSystem.currentDirectory = package.directory; + + await runCapturingPrint(runner, [ + 'sample', + '--current-package', + ]); + + expect(command.plugins, unorderedEquals([package.path])); + }, + ); test('runs only app-facing package of a federated plugin', () async { - const String pluginName = 'foo'; + const pluginName = 'foo'; final Directory groupDir = packagesDir.childDirectory(pluginName); - final RepositoryPackage package = - createFakePlugin(pluginName, groupDir); + final RepositoryPackage package = createFakePlugin( + pluginName, + groupDir, + ); createFakePlugin('${pluginName}_someplatform', groupDir); createFakePackage('${pluginName}_platform_interface', groupDir); packagesDir.fileSystem.currentDirectory = package.directory; - await runCapturingPrint( - runner, ['sample', '--current-package']); + await runCapturingPrint(runner, [ + 'sample', + '--current-package', + ]); expect(command.plugins, unorderedEquals([package.path])); }); - test('runs on a package when run from a package example directory', - () async { - final RepositoryPackage package = createFakePlugin( - 'a_package', packagesDir, - examples: ['a', 'b', 'c']); - createFakePlugin('another_package', packagesDir); - packagesDir.fileSystem.currentDirectory = - package.getExamples().first.directory; - - await runCapturingPrint( - runner, ['sample', '--current-package']); - - expect(command.plugins, unorderedEquals([package.path])); - }); + test( + 'runs on a package when run from a package example directory', + () async { + final RepositoryPackage package = createFakePlugin( + 'a_package', + packagesDir, + examples: ['a', 'b', 'c'], + ); + createFakePlugin('another_package', packagesDir); + packagesDir.fileSystem.currentDirectory = package + .getExamples() + .first + .directory; + + await runCapturingPrint(runner, [ + 'sample', + '--current-package', + ]); + + expect(command.plugins, unorderedEquals([package.path])); + }, + ); - test('runs on a package group when run from the group directory', - () async { - final Directory pluginGroup = packagesDir.childDirectory('a_plugin'); - final RepositoryPackage plugin1 = - createFakePlugin('a_plugin_foo', pluginGroup); - final RepositoryPackage plugin2 = - createFakePlugin('a_plugin_bar', pluginGroup); - createFakePlugin('unrelated_plugin', packagesDir); - packagesDir.fileSystem.currentDirectory = pluginGroup; - - await runCapturingPrint( - runner, ['sample', '--current-package']); - - expect(command.plugins, - unorderedEquals([plugin1.path, plugin2.path])); - }); + test( + 'runs on a package group when run from the group directory', + () async { + final Directory pluginGroup = packagesDir.childDirectory('a_plugin'); + final RepositoryPackage plugin1 = createFakePlugin( + 'a_plugin_foo', + pluginGroup, + ); + final RepositoryPackage plugin2 = createFakePlugin( + 'a_plugin_bar', + pluginGroup, + ); + createFakePlugin('unrelated_plugin', packagesDir); + packagesDir.fileSystem.currentDirectory = pluginGroup; + + await runCapturingPrint(runner, [ + 'sample', + '--current-package', + ]); + + expect( + command.plugins, + unorderedEquals([plugin1.path, plugin2.path]), + ); + }, + ); }); group('test run-on-changed-packages', () { test('all plugins should be tested if there are no changes.', () async { - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); - final RepositoryPackage plugin2 = - createFakePlugin('plugin2', packagesDir); - await runCapturingPrint(runner, - ['sample', '--base-sha=main', '--run-on-changed-packages']); - - expect(command.plugins, - unorderedEquals([plugin1.path, plugin2.path])); + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir, + ); + await runCapturingPrint(runner, [ + 'sample', + '--base-sha=main', + '--run-on-changed-packages', + ]); + + expect( + command.plugins, + unorderedEquals([plugin1.path, plugin2.path]), + ); }); test( - 'all plugins should be tested if there are no plugin related changes.', - () async { - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: 'AUTHORS')), - ]; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); - final RepositoryPackage plugin2 = - createFakePlugin('plugin2', packagesDir); - await runCapturingPrint(runner, - ['sample', '--base-sha=main', '--run-on-changed-packages']); - - expect(command.plugins, - unorderedEquals([plugin1.path, plugin2.path])); - }); + 'all plugins should be tested if there are no plugin related changes.', + () async { + gitProcessRunner.mockProcessesForExecutable['git-diff'] = + [ + FakeProcessInfo(MockProcess(stdout: 'AUTHORS')), + ]; + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir, + ); + await runCapturingPrint(runner, [ + 'sample', + '--base-sha=main', + '--run-on-changed-packages', + ]); + + expect( + command.plugins, + unorderedEquals([plugin1.path, plugin2.path]), + ); + }, + ); test('all plugins should be tested if .ci.yaml changes', () async { gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' .ci.yaml packages/plugin1/CHANGELOG -''')), - ]; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); - final RepositoryPackage plugin2 = - createFakePlugin('plugin2', packagesDir); - final List output = await runCapturingPrint(runner, - ['sample', '--base-sha=main', '--run-on-changed-packages']); - - expect(command.plugins, - unorderedEquals([plugin1.path, plugin2.path])); +''', + ), + ), + ]; + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir, + ); + final List output = await runCapturingPrint(runner, [ + 'sample', + '--base-sha=main', + '--run-on-changed-packages', + ]); + expect( - output, - containsAllInOrder([ - contains('Running for all packages, since a file has changed ' - 'that could affect the entire repository.') - ])); + command.plugins, + unorderedEquals([plugin1.path, plugin2.path]), + ); + expect( + output, + containsAllInOrder([ + contains( + 'Running for all packages, since a file has changed ' + 'that could affect the entire repository.', + ), + ]), + ); }); - test('all plugins should be tested if anything in .ci/ changes', - () async { - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: ''' + test( + 'all plugins should be tested if anything in .ci/ changes', + () async { + gitProcessRunner.mockProcessesForExecutable['git-diff'] = + [ + FakeProcessInfo( + MockProcess( + stdout: ''' .ci/Dockerfile packages/plugin1/CHANGELOG -''')), - ]; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); - final RepositoryPackage plugin2 = - createFakePlugin('plugin2', packagesDir); - final List output = await runCapturingPrint(runner, - ['sample', '--base-sha=main', '--run-on-changed-packages']); - - expect(command.plugins, - unorderedEquals([plugin1.path, plugin2.path])); - expect( +''', + ), + ), + ]; + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir, + ); + final List output = await runCapturingPrint(runner, [ + 'sample', + '--base-sha=main', + '--run-on-changed-packages', + ]); + + expect( + command.plugins, + unorderedEquals([plugin1.path, plugin2.path]), + ); + expect( output, containsAllInOrder([ - contains('Running for all packages, since a file has changed ' - 'that could affect the entire repository.') - ])); - }); + contains( + 'Running for all packages, since a file has changed ' + 'that could affect the entire repository.', + ), + ]), + ); + }, + ); - test('all plugins should be tested if anything in script/ changes.', - () async { - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: ''' + test( + 'all plugins should be tested if anything in script/ changes.', + () async { + gitProcessRunner.mockProcessesForExecutable['git-diff'] = + [ + FakeProcessInfo( + MockProcess( + stdout: ''' script/tool/bin/flutter_plugin_tools.dart packages/plugin1/CHANGELOG -''')), - ]; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); - final RepositoryPackage plugin2 = - createFakePlugin('plugin2', packagesDir); - final List output = await runCapturingPrint(runner, - ['sample', '--base-sha=main', '--run-on-changed-packages']); - - expect(command.plugins, - unorderedEquals([plugin1.path, plugin2.path])); - expect( +''', + ), + ), + ]; + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir, + ); + final List output = await runCapturingPrint(runner, [ + 'sample', + '--base-sha=main', + '--run-on-changed-packages', + ]); + + expect( + command.plugins, + unorderedEquals([plugin1.path, plugin2.path]), + ); + expect( output, containsAllInOrder([ - contains('Running for all packages, since a file has changed ' - 'that could affect the entire repository.') - ])); - }); + contains( + 'Running for all packages, since a file has changed ' + 'that could affect the entire repository.', + ), + ]), + ); + }, + ); - test('all plugins should be tested if the root analysis options change.', - () async { - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: ''' + test( + 'all plugins should be tested if the root analysis options change.', + () async { + gitProcessRunner.mockProcessesForExecutable['git-diff'] = + [ + FakeProcessInfo( + MockProcess( + stdout: ''' analysis_options.yaml packages/plugin1/CHANGELOG -''')), - ]; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); - final RepositoryPackage plugin2 = - createFakePlugin('plugin2', packagesDir); - final List output = await runCapturingPrint(runner, - ['sample', '--base-sha=main', '--run-on-changed-packages']); - - expect(command.plugins, - unorderedEquals([plugin1.path, plugin2.path])); - expect( +''', + ), + ), + ]; + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir, + ); + final List output = await runCapturingPrint(runner, [ + 'sample', + '--base-sha=main', + '--run-on-changed-packages', + ]); + + expect( + command.plugins, + unorderedEquals([plugin1.path, plugin2.path]), + ); + expect( output, containsAllInOrder([ - contains('Running for all packages, since a file has changed ' - 'that could affect the entire repository.') - ])); - }); + contains( + 'Running for all packages, since a file has changed ' + 'that could affect the entire repository.', + ), + ]), + ); + }, + ); - test('all plugins should be tested if formatting options change.', - () async { - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: ''' + test( + 'all plugins should be tested if formatting options change.', + () async { + gitProcessRunner.mockProcessesForExecutable['git-diff'] = + [ + FakeProcessInfo( + MockProcess( + stdout: ''' .clang-format packages/plugin1/CHANGELOG -''')), - ]; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); - final RepositoryPackage plugin2 = - createFakePlugin('plugin2', packagesDir); - final List output = await runCapturingPrint(runner, - ['sample', '--base-sha=main', '--run-on-changed-packages']); - - expect(command.plugins, - unorderedEquals([plugin1.path, plugin2.path])); - expect( +''', + ), + ), + ]; + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir, + ); + final List output = await runCapturingPrint(runner, [ + 'sample', + '--base-sha=main', + '--run-on-changed-packages', + ]); + + expect( + command.plugins, + unorderedEquals([plugin1.path, plugin2.path]), + ); + expect( output, containsAllInOrder([ - contains('Running for all packages, since a file has changed ' - 'that could affect the entire repository.') - ])); - }); + contains( + 'Running for all packages, since a file has changed ' + 'that could affect the entire repository.', + ), + ]), + ); + }, + ); test('Only changed plugin should be tested.', () async { - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ + gitProcessRunner + .mockProcessesForExecutable['git-diff'] = [ FakeProcessInfo(MockProcess(stdout: 'packages/plugin1/plugin1.dart')), ]; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); createFakePlugin('plugin2', packagesDir); - final List output = await runCapturingPrint(runner, - ['sample', '--base-sha=main', '--run-on-changed-packages']); + final List output = await runCapturingPrint(runner, [ + 'sample', + '--base-sha=main', + '--run-on-changed-packages', + ]); expect( - output, - containsAllInOrder([ - contains( - 'Running for all packages that have diffs relative to "main"'), - ])); + output, + containsAllInOrder([ + contains( + 'Running for all packages that have diffs relative to "main"', + ), + ]), + ); expect(command.plugins, unorderedEquals([plugin1.path])); }); - test('multiple files in one plugin should also test the plugin', - () async { - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: ''' + test( + 'multiple files in one plugin should also test the plugin', + () async { + gitProcessRunner.mockProcessesForExecutable['git-diff'] = + [ + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin1/plugin1.dart packages/plugin1/ios/plugin1.m -''')), - ]; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); - createFakePlugin('plugin2', packagesDir); - await runCapturingPrint(runner, - ['sample', '--base-sha=main', '--run-on-changed-packages']); +''', + ), + ), + ]; + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); + createFakePlugin('plugin2', packagesDir); + await runCapturingPrint(runner, [ + 'sample', + '--base-sha=main', + '--run-on-changed-packages', + ]); - expect(command.plugins, unorderedEquals([plugin1.path])); - }); + expect(command.plugins, unorderedEquals([plugin1.path])); + }, + ); - test('multiple plugins changed should test all the changed plugins', - () async { - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: ''' + test( + 'multiple plugins changed should test all the changed plugins', + () async { + gitProcessRunner.mockProcessesForExecutable['git-diff'] = + [ + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin1/plugin1.dart packages/plugin2/ios/plugin2.m -''')), - ]; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); - final RepositoryPackage plugin2 = - createFakePlugin('plugin2', packagesDir); - createFakePlugin('plugin3', packagesDir); - await runCapturingPrint(runner, - ['sample', '--base-sha=main', '--run-on-changed-packages']); - - expect(command.plugins, - unorderedEquals([plugin1.path, plugin2.path])); - }); +''', + ), + ), + ]; + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir, + ); + createFakePlugin('plugin3', packagesDir); + await runCapturingPrint(runner, [ + 'sample', + '--base-sha=main', + '--run-on-changed-packages', + ]); + + expect( + command.plugins, + unorderedEquals([plugin1.path, plugin2.path]), + ); + }, + ); test( - 'multiple plugins inside the same plugin group changed should output the plugin group name', - () async { - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: ''' + 'multiple plugins inside the same plugin group changed should output the plugin group name', + () async { + gitProcessRunner.mockProcessesForExecutable['git-diff'] = + [ + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin1/plugin1/plugin1.dart packages/plugin1/plugin1_platform_interface/plugin1_platform_interface.dart packages/plugin1/plugin1_web/plugin1_web.dart -''')), - ]; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir.childDirectory('plugin1')); - createFakePlugin('plugin2', packagesDir); - createFakePlugin('plugin3', packagesDir); - await runCapturingPrint(runner, - ['sample', '--base-sha=main', '--run-on-changed-packages']); +''', + ), + ), + ]; + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir.childDirectory('plugin1'), + ); + createFakePlugin('plugin2', packagesDir); + createFakePlugin('plugin3', packagesDir); + await runCapturingPrint(runner, [ + 'sample', + '--base-sha=main', + '--run-on-changed-packages', + ]); - expect(command.plugins, unorderedEquals([plugin1.path])); - }); + expect(command.plugins, unorderedEquals([plugin1.path])); + }, + ); test( - 'changing one plugin in a federated group should only include that plugin', - () async { - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: ''' + 'changing one plugin in a federated group should only include that plugin', + () async { + gitProcessRunner.mockProcessesForExecutable['git-diff'] = + [ + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin1/plugin1/plugin1.dart -''')), - ]; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir.childDirectory('plugin1')); - createFakePlugin('plugin1_platform_interface', - packagesDir.childDirectory('plugin1')); - createFakePlugin('plugin1_web', packagesDir.childDirectory('plugin1')); - await runCapturingPrint(runner, - ['sample', '--base-sha=main', '--run-on-changed-packages']); - - expect(command.plugins, unorderedEquals([plugin1.path])); - }); +''', + ), + ), + ]; + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir.childDirectory('plugin1'), + ); + createFakePlugin( + 'plugin1_platform_interface', + packagesDir.childDirectory('plugin1'), + ); + createFakePlugin( + 'plugin1_web', + packagesDir.childDirectory('plugin1'), + ); + await runCapturingPrint(runner, [ + 'sample', + '--base-sha=main', + '--run-on-changed-packages', + ]); + + expect(command.plugins, unorderedEquals([plugin1.path])); + }, + ); test('honors --exclude flag', () async { gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin1/plugin1.dart packages/plugin2/ios/plugin2.m packages/plugin3/plugin3.dart -''')), - ]; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir.childDirectory('plugin1')); +''', + ), + ), + ]; + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir.childDirectory('plugin1'), + ); createFakePlugin('plugin2', packagesDir); createFakePlugin('plugin3', packagesDir); await runCapturingPrint(runner, [ 'sample', '--exclude=plugin2,plugin3', '--base-sha=main', - '--run-on-changed-packages' + '--run-on-changed-packages', ]); expect(command.plugins, unorderedEquals([plugin1.path])); @@ -811,44 +1106,55 @@ packages/plugin3/plugin3.dart test('honors --filter-packages-to flag', () async { gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin1/plugin1.dart packages/plugin2/ios/plugin2.m packages/plugin3/plugin3.dart -''')), - ]; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir.childDirectory('plugin1')); +''', + ), + ), + ]; + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir.childDirectory('plugin1'), + ); createFakePlugin('plugin2', packagesDir); createFakePlugin('plugin3', packagesDir); await runCapturingPrint(runner, [ 'sample', '--filter-packages-to=plugin1', '--base-sha=main', - '--run-on-changed-packages' + '--run-on-changed-packages', ]); expect(command.plugins, unorderedEquals([plugin1.path])); }); - test( - 'honors --filter-packages-to flag when a file is changed that makes ' + test('honors --filter-packages-to flag when a file is changed that makes ' 'all packages potentially changed', () async { gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' .ci.yaml -''')), - ]; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir.childDirectory('plugin1')); +''', + ), + ), + ]; + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir.childDirectory('plugin1'), + ); createFakePlugin('plugin2', packagesDir); createFakePlugin('plugin3', packagesDir); await runCapturingPrint(runner, [ 'sample', '--filter-packages-to=plugin1', '--base-sha=main', - '--run-on-changed-packages' + '--run-on-changed-packages', ]); expect(command.plugins, unorderedEquals([plugin1.path])); @@ -857,41 +1163,57 @@ packages/plugin3/plugin3.dart test('--filter-packages-to handles federated plugin groups', () async { gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' packages/a_plugin/a_plugin/lib/foo.dart packages/a_plugin/a_plugin_impl/lib/foo.dart packages/a_plugin/a_plugin_platform_interface/lib/foo.dart -''')), - ]; +''', + ), + ), + ]; final Directory groupDir = packagesDir.childDirectory('a_plugin'); - final RepositoryPackage plugin1 = - createFakePlugin('a_plugin', groupDir); - final RepositoryPackage plugin2 = - createFakePlugin('a_plugin_impl', groupDir); - final RepositoryPackage plugin3 = - createFakePlugin('a_plugin_platform_interface', groupDir); + final RepositoryPackage plugin1 = createFakePlugin( + 'a_plugin', + groupDir, + ); + final RepositoryPackage plugin2 = createFakePlugin( + 'a_plugin_impl', + groupDir, + ); + final RepositoryPackage plugin3 = createFakePlugin( + 'a_plugin_platform_interface', + groupDir, + ); await runCapturingPrint(runner, [ 'sample', '--filter-packages-to=a_plugin', '--base-sha=main', - '--run-on-changed-packages' + '--run-on-changed-packages', ]); expect( - command.plugins, - unorderedEquals( - [plugin1.path, plugin2.path, plugin3.path])); + command.plugins, + unorderedEquals([plugin1.path, plugin2.path, plugin3.path]), + ); }); test('--filter-packages-to and --exclude work together', () async { gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' .ci.yaml -''')), - ]; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir.childDirectory('plugin1')); +''', + ), + ), + ]; + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir.childDirectory('plugin1'), + ); createFakePlugin('plugin2', packagesDir); createFakePlugin('plugin3', packagesDir); await runCapturingPrint(runner, [ @@ -899,7 +1221,7 @@ packages/a_plugin/a_plugin_platform_interface/lib/foo.dart '--filter-packages-to=plugin1,plugin2', '--exclude=plugin2', '--base-sha=main', - '--run-on-changed-packages' + '--run-on-changed-packages', ]); expect(command.plugins, unorderedEquals([plugin1.path])); @@ -909,104 +1231,142 @@ packages/a_plugin/a_plugin_platform_interface/lib/foo.dart group('test run-on-dirty-packages', () { test('no packages should be tested if there are no changes.', () async { createFakePackage('a_package', packagesDir); - await runCapturingPrint( - runner, ['sample', '--run-on-dirty-packages']); + await runCapturingPrint(runner, [ + 'sample', + '--run-on-dirty-packages', + ]); expect(command.plugins, unorderedEquals([])); }); test( - 'no packages should be tested if there are no plugin related changes.', - () async { - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: 'AUTHORS')), - ]; - createFakePackage('a_package', packagesDir); - await runCapturingPrint( - runner, ['sample', '--run-on-dirty-packages']); - - expect(command.plugins, unorderedEquals([])); - }); + 'no packages should be tested if there are no plugin related changes.', + () async { + gitProcessRunner.mockProcessesForExecutable['git-diff'] = + [ + FakeProcessInfo(MockProcess(stdout: 'AUTHORS')), + ]; + createFakePackage('a_package', packagesDir); + await runCapturingPrint(runner, [ + 'sample', + '--run-on-dirty-packages', + ]); + + expect(command.plugins, unorderedEquals([])); + }, + ); - test('no packages should be tested even if special repo files change.', - () async { - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: ''' + test( + 'no packages should be tested even if special repo files change.', + () async { + gitProcessRunner.mockProcessesForExecutable['git-diff'] = + [ + FakeProcessInfo( + MockProcess( + stdout: ''' .ci.yaml .ci/Dockerfile .clang-format analysis_options.yaml script/tool/bin/flutter_plugin_tools.dart -''')), - ]; - createFakePackage('a_package', packagesDir); - await runCapturingPrint( - runner, ['sample', '--run-on-dirty-packages']); - - expect(command.plugins, unorderedEquals([])); - }); +''', + ), + ), + ]; + createFakePackage('a_package', packagesDir); + await runCapturingPrint(runner, [ + 'sample', + '--run-on-dirty-packages', + ]); + + expect(command.plugins, unorderedEquals([])); + }, + ); test('Only changed packages should be tested.', () async { gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo( - MockProcess(stdout: 'packages/a_package/lib/a_package.dart')), - ]; - final RepositoryPackage packageA = - createFakePackage('a_package', packagesDir); + FakeProcessInfo( + MockProcess(stdout: 'packages/a_package/lib/a_package.dart'), + ), + ]; + final RepositoryPackage packageA = createFakePackage( + 'a_package', + packagesDir, + ); createFakePlugin('b_package', packagesDir); - final List output = await runCapturingPrint( - runner, ['sample', '--run-on-dirty-packages']); + final List output = await runCapturingPrint(runner, [ + 'sample', + '--run-on-dirty-packages', + ]); expect( - output, - containsAllInOrder([ - contains( - 'Running for all packages that have uncommitted changes'), - ])); + output, + containsAllInOrder([ + contains('Running for all packages that have uncommitted changes'), + ]), + ); expect(command.plugins, unorderedEquals([packageA.path])); }); - test('multiple packages changed should test all the changed packages', - () async { - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: ''' + test( + 'multiple packages changed should test all the changed packages', + () async { + gitProcessRunner.mockProcessesForExecutable['git-diff'] = + [ + FakeProcessInfo( + MockProcess( + stdout: ''' packages/a_package/lib/a_package.dart packages/b_package/lib/src/foo.dart -''')), - ]; - final RepositoryPackage packageA = - createFakePackage('a_package', packagesDir); - final RepositoryPackage packageB = - createFakePackage('b_package', packagesDir); - createFakePackage('c_package', packagesDir); - await runCapturingPrint( - runner, ['sample', '--run-on-dirty-packages']); - - expect(command.plugins, - unorderedEquals([packageA.path, packageB.path])); - }); +''', + ), + ), + ]; + final RepositoryPackage packageA = createFakePackage( + 'a_package', + packagesDir, + ); + final RepositoryPackage packageB = createFakePackage( + 'b_package', + packagesDir, + ); + createFakePackage('c_package', packagesDir); + await runCapturingPrint(runner, [ + 'sample', + '--run-on-dirty-packages', + ]); + + expect( + command.plugins, + unorderedEquals([packageA.path, packageB.path]), + ); + }, + ); test('honors --exclude flag', () async { gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' packages/a_package/lib/a_package.dart packages/b_package/lib/src/foo.dart -''')), - ]; - final RepositoryPackage packageA = - createFakePackage('a_package', packagesDir); +''', + ), + ), + ]; + final RepositoryPackage packageA = createFakePackage( + 'a_package', + packagesDir, + ); createFakePackage('b_package', packagesDir); createFakePackage('c_package', packagesDir); await runCapturingPrint(runner, [ 'sample', '--exclude=b_package', - '--run-on-dirty-packages' + '--run-on-dirty-packages', ]); expect(command.plugins, unorderedEquals([packageA.path])); @@ -1015,238 +1375,286 @@ packages/b_package/lib/src/foo.dart }); group('--packages-for-branch', () { - test('only tests changed packages relative to the merge base on a branch', - () async { - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: 'packages/plugin1/plugin1.dart')), - ]; - gitProcessRunner.mockProcessesForExecutable['git-rev-parse'] = - [ - FakeProcessInfo(MockProcess(stdout: 'a-branch')), - ]; - gitProcessRunner.mockProcessesForExecutable['git-merge-base'] = - [ - FakeProcessInfo(MockProcess(exitCode: 1), ['--is-ancestor']), - FakeProcessInfo(MockProcess(stdout: 'abc123'), - ['--fork-point']), // finding merge base - ]; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); - createFakePlugin('plugin2', packagesDir); + test( + 'only tests changed packages relative to the merge base on a branch', + () async { + gitProcessRunner + .mockProcessesForExecutable['git-diff'] = [ + FakeProcessInfo(MockProcess(stdout: 'packages/plugin1/plugin1.dart')), + ]; + gitProcessRunner.mockProcessesForExecutable['git-rev-parse'] = + [FakeProcessInfo(MockProcess(stdout: 'a-branch'))]; + gitProcessRunner + .mockProcessesForExecutable['git-merge-base'] = [ + FakeProcessInfo(MockProcess(exitCode: 1), ['--is-ancestor']), + FakeProcessInfo(MockProcess(stdout: 'abc123'), [ + '--fork-point', + ]), // finding merge base + ]; + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); + createFakePlugin('plugin2', packagesDir); - final List output = await runCapturingPrint( - runner, ['sample', '--packages-for-branch']); + final List output = await runCapturingPrint(runner, [ + 'sample', + '--packages-for-branch', + ]); - expect(command.plugins, unorderedEquals([plugin1.path])); - expect( + expect(command.plugins, unorderedEquals([plugin1.path])); + expect( output, containsAllInOrder([ contains('--packages-for-branch: running on branch "a-branch"'), contains( - 'Running for all packages that have diffs relative to "abc123"'), - ])); - // Ensure that it's diffing against the merge-base. - expect( + 'Running for all packages that have diffs relative to "abc123"', + ), + ]), + ); + // Ensure that it's diffing against the merge-base. + expect( gitProcessRunner.recordedCalls, contains( - const ProcessCall( - 'git-diff', ['--name-only', 'abc123', 'HEAD'], null), - )); - }); + const ProcessCall('git-diff', [ + '--name-only', + 'abc123', + 'HEAD', + ], null), + ), + ); + }, + ); - test('only tests changed packages relative to the previous commit on main', - () async { - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: 'packages/plugin1/plugin1.dart')), - ]; - gitProcessRunner.mockProcessesForExecutable['git-rev-parse'] = - [ - FakeProcessInfo(MockProcess(stdout: 'main')), - ]; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); - createFakePlugin('plugin2', packagesDir); + test( + 'only tests changed packages relative to the previous commit on main', + () async { + gitProcessRunner + .mockProcessesForExecutable['git-diff'] = [ + FakeProcessInfo(MockProcess(stdout: 'packages/plugin1/plugin1.dart')), + ]; + gitProcessRunner.mockProcessesForExecutable['git-rev-parse'] = + [FakeProcessInfo(MockProcess(stdout: 'main'))]; + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); + createFakePlugin('plugin2', packagesDir); - final List output = await runCapturingPrint( - runner, ['sample', '--packages-for-branch']); + final List output = await runCapturingPrint(runner, [ + 'sample', + '--packages-for-branch', + ]); - expect(command.plugins, unorderedEquals([plugin1.path])); - expect( + expect(command.plugins, unorderedEquals([plugin1.path])); + expect( output, containsAllInOrder([ contains('--packages-for-branch: running on default branch.'), contains( - '--packages-for-branch: using parent commit as the diff base'), + '--packages-for-branch: using parent commit as the diff base', + ), contains( - 'Running for all packages that have diffs relative to "HEAD~"'), - ])); - // Ensure that it's diffing against the prior commit. - expect( + 'Running for all packages that have diffs relative to "HEAD~"', + ), + ]), + ); + // Ensure that it's diffing against the prior commit. + expect( gitProcessRunner.recordedCalls, contains( - const ProcessCall( - 'git-diff', ['--name-only', 'HEAD~', 'HEAD'], null), - )); - }); + const ProcessCall('git-diff', [ + '--name-only', + 'HEAD~', + 'HEAD', + ], null), + ), + ); + }, + ); - test( - 'only tests changed packages relative to the previous commit if ' + test('only tests changed packages relative to the previous commit if ' 'running on a specific hash from main', () async { - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ + gitProcessRunner + .mockProcessesForExecutable['git-diff'] = [ FakeProcessInfo(MockProcess(stdout: 'packages/plugin1/plugin1.dart')), ]; gitProcessRunner.mockProcessesForExecutable['git-rev-parse'] = - [ - FakeProcessInfo(MockProcess(stdout: 'HEAD')), - ]; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); + [FakeProcessInfo(MockProcess(stdout: 'HEAD'))]; + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); createFakePlugin('plugin2', packagesDir); - final List output = await runCapturingPrint( - runner, ['sample', '--packages-for-branch']); + final List output = await runCapturingPrint(runner, [ + 'sample', + '--packages-for-branch', + ]); expect(command.plugins, unorderedEquals([plugin1.path])); expect( - output, - containsAllInOrder([ - contains( - '--packages-for-branch: running on a commit from default branch.'), - contains( - '--packages-for-branch: using parent commit as the diff base'), - contains( - 'Running for all packages that have diffs relative to "HEAD~"'), - ])); + output, + containsAllInOrder([ + contains( + '--packages-for-branch: running on a commit from default branch.', + ), + contains( + '--packages-for-branch: using parent commit as the diff base', + ), + contains( + 'Running for all packages that have diffs relative to "HEAD~"', + ), + ]), + ); // Ensure that it's diffing against the prior commit. expect( - gitProcessRunner.recordedCalls, - contains( - const ProcessCall( - 'git-diff', ['--name-only', 'HEAD~', 'HEAD'], null), - )); + gitProcessRunner.recordedCalls, + contains( + const ProcessCall('git-diff', [ + '--name-only', + 'HEAD~', + 'HEAD', + ], null), + ), + ); }); - test( - 'only tests changed packages relative to the previous commit if ' + test('only tests changed packages relative to the previous commit if ' 'running on a specific hash from origin/main', () async { - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ + gitProcessRunner + .mockProcessesForExecutable['git-diff'] = [ FakeProcessInfo(MockProcess(stdout: 'packages/plugin1/plugin1.dart')), ]; gitProcessRunner.mockProcessesForExecutable['git-rev-parse'] = - [ - FakeProcessInfo(MockProcess(stdout: 'HEAD')), - ]; + [FakeProcessInfo(MockProcess(stdout: 'HEAD'))]; gitProcessRunner.mockProcessesForExecutable['git-merge-base'] = [ - FakeProcessInfo(MockProcess(exitCode: 128), [ - '--is-ancestor', - 'HEAD', - 'main' - ]), // Fail with a non-1 exit code for 'main' - FakeProcessInfo(MockProcess(), [ - '--is-ancestor', - 'HEAD', - 'origin/main' - ]), // Succeed for the variant. - ]; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); + FakeProcessInfo(MockProcess(exitCode: 128), [ + '--is-ancestor', + 'HEAD', + 'main', + ]), // Fail with a non-1 exit code for 'main' + FakeProcessInfo(MockProcess(), [ + '--is-ancestor', + 'HEAD', + 'origin/main', + ]), // Succeed for the variant. + ]; + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); createFakePlugin('plugin2', packagesDir); - final List output = await runCapturingPrint( - runner, ['sample', '--packages-for-branch']); + final List output = await runCapturingPrint(runner, [ + 'sample', + '--packages-for-branch', + ]); expect(command.plugins, unorderedEquals([plugin1.path])); expect( - output, - containsAllInOrder([ - contains( - '--packages-for-branch: running on a commit from default branch.'), - contains( - '--packages-for-branch: using parent commit as the diff base'), - contains( - 'Running for all packages that have diffs relative to "HEAD~"'), - ])); + output, + containsAllInOrder([ + contains( + '--packages-for-branch: running on a commit from default branch.', + ), + contains( + '--packages-for-branch: using parent commit as the diff base', + ), + contains( + 'Running for all packages that have diffs relative to "HEAD~"', + ), + ]), + ); // Ensure that it's diffing against the prior commit. expect( - gitProcessRunner.recordedCalls, - contains( - const ProcessCall( - 'git-diff', ['--name-only', 'HEAD~', 'HEAD'], null), - )); + gitProcessRunner.recordedCalls, + contains( + const ProcessCall('git-diff', [ + '--name-only', + 'HEAD~', + 'HEAD', + ], null), + ), + ); }); test( - 'only tests changed packages relative to the previous commit on master', - () async { - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: 'packages/plugin1/plugin1.dart')), - ]; - gitProcessRunner.mockProcessesForExecutable['git-rev-parse'] = - [ - FakeProcessInfo(MockProcess(stdout: 'master')), - ]; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); - createFakePlugin('plugin2', packagesDir); + 'only tests changed packages relative to the previous commit on master', + () async { + gitProcessRunner + .mockProcessesForExecutable['git-diff'] = [ + FakeProcessInfo(MockProcess(stdout: 'packages/plugin1/plugin1.dart')), + ]; + gitProcessRunner.mockProcessesForExecutable['git-rev-parse'] = + [FakeProcessInfo(MockProcess(stdout: 'master'))]; + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); + createFakePlugin('plugin2', packagesDir); - final List output = await runCapturingPrint( - runner, ['sample', '--packages-for-branch']); + final List output = await runCapturingPrint(runner, [ + 'sample', + '--packages-for-branch', + ]); - expect(command.plugins, unorderedEquals([plugin1.path])); - expect( + expect(command.plugins, unorderedEquals([plugin1.path])); + expect( output, containsAllInOrder([ contains('--packages-for-branch: running on default branch.'), contains( - '--packages-for-branch: using parent commit as the diff base'), + '--packages-for-branch: using parent commit as the diff base', + ), contains( - 'Running for all packages that have diffs relative to "HEAD~"'), - ])); - // Ensure that it's diffing against the prior commit. - expect( + 'Running for all packages that have diffs relative to "HEAD~"', + ), + ]), + ); + // Ensure that it's diffing against the prior commit. + expect( gitProcessRunner.recordedCalls, contains( - const ProcessCall( - 'git-diff', ['--name-only', 'HEAD~', 'HEAD'], null), - )); - }); + const ProcessCall('git-diff', [ + '--name-only', + 'HEAD~', + 'HEAD', + ], null), + ), + ); + }, + ); test('throws if getting the branch fails', () async { - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ + gitProcessRunner + .mockProcessesForExecutable['git-diff'] = [ FakeProcessInfo(MockProcess(stdout: 'packages/plugin1/plugin1.dart')), ]; gitProcessRunner.mockProcessesForExecutable['git-rev-parse'] = - [ - FakeProcessInfo(MockProcess(exitCode: 1)), - ]; + [FakeProcessInfo(MockProcess(exitCode: 1))]; Error? commandError; final List output = await runCapturingPrint( - runner, ['sample', '--packages-for-branch'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['sample', '--packages-for-branch'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Unable to determine branch'), - ])); + output, + containsAllInOrder([contains('Unable to determine branch')]), + ); }); }); group('sharding', () { test('distributes evenly when evenly divisible', () async { - final List> expectedShards = - >[ + final expectedShards = >[ [ createFakePackage('package1', packagesDir), createFakePackage('package2', packagesDir), @@ -1264,10 +1672,12 @@ packages/b_package/lib/src/foo.dart ], ]; - for (int i = 0; i < expectedShards.length; ++i) { + for (var i = 0; i < expectedShards.length; ++i) { final SamplePackageCommand localCommand = configureCommand(); - final CommandRunner localRunner = - CommandRunner('common_command', 'Shard testing'); + final localRunner = CommandRunner( + 'common_command', + 'Shard testing', + ); localRunner.addCommand(localCommand); await runCapturingPrint(localRunner, [ @@ -1276,51 +1686,60 @@ packages/b_package/lib/src/foo.dart '--shardCount=3', ]); expect( - localCommand.plugins, - unorderedEquals(expectedShards[i] + localCommand.plugins, + unorderedEquals( + expectedShards[i] .map((RepositoryPackage package) => package.path) - .toList())); + .toList(), + ), + ); } }); - test('distributes as evenly as possible when not evenly divisible', - () async { - final List> expectedShards = - >[ - [ - createFakePackage('package1', packagesDir), - createFakePackage('package2', packagesDir), - createFakePackage('package3', packagesDir), - ], - [ - createFakePackage('package4', packagesDir), - createFakePackage('package5', packagesDir), - createFakePackage('package6', packagesDir), - ], - [ - createFakePackage('package7', packagesDir), - createFakePackage('package8', packagesDir), - ], - ]; - - for (int i = 0; i < expectedShards.length; ++i) { - final SamplePackageCommand localCommand = configureCommand(); - final CommandRunner localRunner = - CommandRunner('common_command', 'Shard testing'); - localRunner.addCommand(localCommand); + test( + 'distributes as evenly as possible when not evenly divisible', + () async { + final expectedShards = >[ + [ + createFakePackage('package1', packagesDir), + createFakePackage('package2', packagesDir), + createFakePackage('package3', packagesDir), + ], + [ + createFakePackage('package4', packagesDir), + createFakePackage('package5', packagesDir), + createFakePackage('package6', packagesDir), + ], + [ + createFakePackage('package7', packagesDir), + createFakePackage('package8', packagesDir), + ], + ]; - await runCapturingPrint(localRunner, [ - 'sample', - '--shardIndex=$i', - '--shardCount=3', - ]); - expect( + for (var i = 0; i < expectedShards.length; ++i) { + final SamplePackageCommand localCommand = configureCommand(); + final localRunner = CommandRunner( + 'common_command', + 'Shard testing', + ); + localRunner.addCommand(localCommand); + + await runCapturingPrint(localRunner, [ + 'sample', + '--shardIndex=$i', + '--shardCount=3', + ]); + expect( localCommand.plugins, - unorderedEquals(expectedShards[i] - .map((RepositoryPackage package) => package.path) - .toList())); - } - }); + unorderedEquals( + expectedShards[i] + .map((RepositoryPackage package) => package.path) + .toList(), + ), + ); + } + }, + ); // In CI (which is the use case for sharding) we often want to run muliple // commands on the same set of packages, but the exclusion lists for those @@ -1331,8 +1750,7 @@ packages/b_package/lib/src/foo.dart // excluding some plugins from the later step shouldn't change what's tested // in each shard, as it may no longer align with what was built. test('counts excluded plugins when sharding', () async { - final List> expectedShards = - >[ + final expectedShards = >[ [ createFakePackage('package1', packagesDir), createFakePackage('package2', packagesDir), @@ -1343,18 +1761,18 @@ packages/b_package/lib/src/foo.dart createFakePackage('package5', packagesDir), createFakePackage('package6', packagesDir), ], - [ - createFakePackage('package7', packagesDir), - ], + [createFakePackage('package7', packagesDir)], ]; // These would be in the last shard, but are excluded. createFakePackage('package8', packagesDir); createFakePackage('package9', packagesDir); - for (int i = 0; i < expectedShards.length; ++i) { + for (var i = 0; i < expectedShards.length; ++i) { final SamplePackageCommand localCommand = configureCommand(); - final CommandRunner localRunner = - CommandRunner('common_command', 'Shard testing'); + final localRunner = CommandRunner( + 'common_command', + 'Shard testing', + ); localRunner.addCommand(localCommand); await runCapturingPrint(localRunner, [ @@ -1364,10 +1782,13 @@ packages/b_package/lib/src/foo.dart '--exclude=package8,package9', ]); expect( - localCommand.plugins, - unorderedEquals(expectedShards[i] + localCommand.plugins, + unorderedEquals( + expectedShards[i] .map((RepositoryPackage package) => package.path) - .toList())); + .toList(), + ), + ); } }); }); diff --git a/script/tool/test/common/package_command_test.mocks.dart b/script/tool/test/common/package_command_test.mocks.dart index 1ac9d406f1e7..fbbcd56dd0b6 100644 --- a/script/tool/test/common/package_command_test.mocks.dart +++ b/script/tool/test/common/package_command_test.mocks.dart @@ -29,24 +29,14 @@ import 'package:mockito/src/dummies.dart' as _i5; // ignore_for_file: subtype_of_sealed_class class _FakeCommit_0 extends _i1.SmartFake implements _i2.Commit { - _FakeCommit_0( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); + _FakeCommit_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } class _FakeBranchReference_1 extends _i1.SmartFake implements _i3.BranchReference { - _FakeBranchReference_1( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); + _FakeBranchReference_1(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); } /// A class which mocks [GitDir]. @@ -58,79 +48,69 @@ class MockGitDir extends _i1.Mock implements _i4.GitDir { } @override - String get path => (super.noSuchMethod( - Invocation.getter(#path), - returnValue: _i5.dummyValue( - this, - Invocation.getter(#path), - ), - ) as String); + String get path => + (super.noSuchMethod( + Invocation.getter(#path), + returnValue: _i5.dummyValue(this, Invocation.getter(#path)), + ) + as String); @override _i6.Future commitCount([String? branchName = r'HEAD']) => (super.noSuchMethod( - Invocation.method( - #commitCount, - [branchName], - ), - returnValue: _i6.Future.value(0), - ) as _i6.Future); + Invocation.method(#commitCount, [branchName]), + returnValue: _i6.Future.value(0), + ) + as _i6.Future); @override _i6.Future<_i2.Commit> commitFromRevision(String? revision) => (super.noSuchMethod( - Invocation.method( - #commitFromRevision, - [revision], - ), - returnValue: _i6.Future<_i2.Commit>.value(_FakeCommit_0( - this, - Invocation.method( - #commitFromRevision, - [revision], - ), - )), - ) as _i6.Future<_i2.Commit>); + Invocation.method(#commitFromRevision, [revision]), + returnValue: _i6.Future<_i2.Commit>.value( + _FakeCommit_0( + this, + Invocation.method(#commitFromRevision, [revision]), + ), + ), + ) + as _i6.Future<_i2.Commit>); @override _i6.Future> commits([String? branchName = r'HEAD']) => (super.noSuchMethod( - Invocation.method( - #commits, - [branchName], - ), - returnValue: - _i6.Future>.value({}), - ) as _i6.Future>); + Invocation.method(#commits, [branchName]), + returnValue: _i6.Future>.value( + {}, + ), + ) + as _i6.Future>); @override _i6.Future<_i3.BranchReference?> branchReference(String? branchName) => (super.noSuchMethod( - Invocation.method( - #branchReference, - [branchName], - ), - returnValue: _i6.Future<_i3.BranchReference?>.value(), - ) as _i6.Future<_i3.BranchReference?>); + Invocation.method(#branchReference, [branchName]), + returnValue: _i6.Future<_i3.BranchReference?>.value(), + ) + as _i6.Future<_i3.BranchReference?>); @override - _i6.Future> branches() => (super.noSuchMethod( - Invocation.method( - #branches, - [], - ), - returnValue: _i6.Future>.value( - <_i3.BranchReference>[]), - ) as _i6.Future>); + _i6.Future> branches() => + (super.noSuchMethod( + Invocation.method(#branches, []), + returnValue: _i6.Future>.value( + <_i3.BranchReference>[], + ), + ) + as _i6.Future>); @override - _i6.Stream<_i7.Tag> tags() => (super.noSuchMethod( - Invocation.method( - #tags, - [], - ), - returnValue: _i6.Stream<_i7.Tag>.empty(), - ) as _i6.Stream<_i7.Tag>); + _i6.Stream<_i7.Tag> tags() => + (super.noSuchMethod( + Invocation.method(#tags, []), + returnValue: _i6.Stream<_i7.Tag>.empty(), + ) + as _i6.Stream<_i7.Tag>); @override _i6.Future> showRef({ @@ -138,33 +118,25 @@ class MockGitDir extends _i1.Mock implements _i4.GitDir { bool? tags = false, }) => (super.noSuchMethod( - Invocation.method( - #showRef, - [], - { - #heads: heads, - #tags: tags, - }, - ), - returnValue: _i6.Future>.value( - <_i8.CommitReference>[]), - ) as _i6.Future>); + Invocation.method(#showRef, [], {#heads: heads, #tags: tags}), + returnValue: _i6.Future>.value( + <_i8.CommitReference>[], + ), + ) + as _i6.Future>); @override - _i6.Future<_i3.BranchReference> currentBranch() => (super.noSuchMethod( - Invocation.method( - #currentBranch, - [], - ), - returnValue: - _i6.Future<_i3.BranchReference>.value(_FakeBranchReference_1( - this, - Invocation.method( - #currentBranch, - [], - ), - )), - ) as _i6.Future<_i3.BranchReference>); + _i6.Future<_i3.BranchReference> currentBranch() => + (super.noSuchMethod( + Invocation.method(#currentBranch, []), + returnValue: _i6.Future<_i3.BranchReference>.value( + _FakeBranchReference_1( + this, + Invocation.method(#currentBranch, []), + ), + ), + ) + as _i6.Future<_i3.BranchReference>); @override _i6.Future> lsTree( @@ -173,16 +145,16 @@ class MockGitDir extends _i1.Mock implements _i4.GitDir { String? path, }) => (super.noSuchMethod( - Invocation.method( - #lsTree, - [treeish], - { - #subTreesOnly: subTreesOnly, - #path: path, - }, - ), - returnValue: _i6.Future>.value(<_i9.TreeEntry>[]), - ) as _i6.Future>); + Invocation.method( + #lsTree, + [treeish], + {#subTreesOnly: subTreesOnly, #path: path}, + ), + returnValue: _i6.Future>.value( + <_i9.TreeEntry>[], + ), + ) + as _i6.Future>); @override _i6.Future createOrUpdateBranch( @@ -191,16 +163,14 @@ class MockGitDir extends _i1.Mock implements _i4.GitDir { String? commitMessage, ) => (super.noSuchMethod( - Invocation.method( - #createOrUpdateBranch, - [ - branchName, - treeSha, - commitMessage, - ], - ), - returnValue: _i6.Future.value(), - ) as _i6.Future); + Invocation.method(#createOrUpdateBranch, [ + branchName, + treeSha, + commitMessage, + ]), + returnValue: _i6.Future.value(), + ) + as _i6.Future); @override _i6.Future commitTree( @@ -209,36 +179,33 @@ class MockGitDir extends _i1.Mock implements _i4.GitDir { List? parentCommitShas, }) => (super.noSuchMethod( - Invocation.method( - #commitTree, - [ - treeSha, - commitMessage, - ], - {#parentCommitShas: parentCommitShas}, - ), - returnValue: _i6.Future.value(_i5.dummyValue( - this, - Invocation.method( - #commitTree, - [ - treeSha, - commitMessage, - ], - {#parentCommitShas: parentCommitShas}, - ), - )), - ) as _i6.Future); + Invocation.method( + #commitTree, + [treeSha, commitMessage], + {#parentCommitShas: parentCommitShas}, + ), + returnValue: _i6.Future.value( + _i5.dummyValue( + this, + Invocation.method( + #commitTree, + [treeSha, commitMessage], + {#parentCommitShas: parentCommitShas}, + ), + ), + ), + ) + as _i6.Future); @override _i6.Future> writeObjects(List? paths) => (super.noSuchMethod( - Invocation.method( - #writeObjects, - [paths], - ), - returnValue: _i6.Future>.value({}), - ) as _i6.Future>); + Invocation.method(#writeObjects, [paths]), + returnValue: _i6.Future>.value( + {}, + ), + ) + as _i6.Future>); @override _i6.Future<_i10.ProcessResult> runCommand( @@ -247,36 +214,31 @@ class MockGitDir extends _i1.Mock implements _i4.GitDir { bool? echoOutput = false, }) => (super.noSuchMethod( - Invocation.method( - #runCommand, - [args], - { - #throwOnError: throwOnError, - #echoOutput: echoOutput, - }, - ), - returnValue: _i6.Future<_i10.ProcessResult>.value( - _i5.dummyValue<_i10.ProcessResult>( - this, - Invocation.method( - #runCommand, - [args], - { - #throwOnError: throwOnError, - #echoOutput: echoOutput, - }, - ), - )), - ) as _i6.Future<_i10.ProcessResult>); + Invocation.method( + #runCommand, + [args], + {#throwOnError: throwOnError, #echoOutput: echoOutput}, + ), + returnValue: _i6.Future<_i10.ProcessResult>.value( + _i5.dummyValue<_i10.ProcessResult>( + this, + Invocation.method( + #runCommand, + [args], + {#throwOnError: throwOnError, #echoOutput: echoOutput}, + ), + ), + ), + ) + as _i6.Future<_i10.ProcessResult>); @override - _i6.Future isWorkingTreeClean() => (super.noSuchMethod( - Invocation.method( - #isWorkingTreeClean, - [], - ), - returnValue: _i6.Future.value(false), - ) as _i6.Future); + _i6.Future isWorkingTreeClean() => + (super.noSuchMethod( + Invocation.method(#isWorkingTreeClean, []), + returnValue: _i6.Future.value(false), + ) + as _i6.Future); @override _i6.Future<_i2.Commit?> updateBranch( @@ -285,16 +247,14 @@ class MockGitDir extends _i1.Mock implements _i4.GitDir { String? commitMessage, ) => (super.noSuchMethod( - Invocation.method( - #updateBranch, - [ - branchName, - populater, - commitMessage, - ], - ), - returnValue: _i6.Future<_i2.Commit?>.value(), - ) as _i6.Future<_i2.Commit?>); + Invocation.method(#updateBranch, [ + branchName, + populater, + commitMessage, + ]), + returnValue: _i6.Future<_i2.Commit?>.value(), + ) + as _i6.Future<_i2.Commit?>); @override _i6.Future<_i2.Commit?> updateBranchWithDirectoryContents( @@ -303,14 +263,12 @@ class MockGitDir extends _i1.Mock implements _i4.GitDir { String? commitMessage, ) => (super.noSuchMethod( - Invocation.method( - #updateBranchWithDirectoryContents, - [ - branchName, - sourceDirectoryPath, - commitMessage, - ], - ), - returnValue: _i6.Future<_i2.Commit?>.value(), - ) as _i6.Future<_i2.Commit?>); + Invocation.method(#updateBranchWithDirectoryContents, [ + branchName, + sourceDirectoryPath, + commitMessage, + ]), + returnValue: _i6.Future<_i2.Commit?>.value(), + ) + as _i6.Future<_i2.Commit?>); } diff --git a/script/tool/test/common/package_looping_command_test.dart b/script/tool/test/common/package_looping_command_test.dart index 4f036d093421..1589e748b435 100644 --- a/script/tool/test/common/package_looping_command_test.dart +++ b/script/tool/test/common/package_looping_command_test.dart @@ -52,8 +52,11 @@ const String _throwFile = 'throw'; /// Writes a file to [package] to control the behavior of /// [TestPackageLoopingCommand] for that package. -void _addResultFile(RepositoryPackage package, _ResultFileType type, - {String? contents}) { +void _addResultFile( + RepositoryPackage package, + _ResultFileType type, { + String? contents, +}) { final File file = package.directory.childFile(_filenameForType(type)); file.createSync(); if (contents != null) { @@ -128,72 +131,86 @@ void main() { void Function(Error error)? errorHandler, }) async { late CommandRunner runner; - runner = CommandRunner('test_package_looping_command', - 'Test for base package looping functionality'); - runner.addCommand(command); - return runCapturingPrint( - runner, - [command.name, ...arguments], - errorHandler: errorHandler, + runner = CommandRunner( + 'test_package_looping_command', + 'Test for base package looping functionality', ); + runner.addCommand(command); + return runCapturingPrint(runner, [ + command.name, + ...arguments, + ], errorHandler: errorHandler); } group('tool exit', () { test('is handled during initializeRun', () async { - final TestPackageLoopingCommand command = - createTestCommand(failsDuringInit: true); + final TestPackageLoopingCommand command = createTestCommand( + failsDuringInit: true, + ); expect(() => runCommand(command), throwsA(isA())); }); test('does not stop looping on error', () async { createFakePackage('package_a', packagesDir); - final RepositoryPackage failingPackage = - createFakePlugin('package_b', packagesDir); + final RepositoryPackage failingPackage = createFakePlugin( + 'package_b', + packagesDir, + ); createFakePackage('package_c', packagesDir); _addResultFile(failingPackage, _ResultFileType.errors); - final TestPackageLoopingCommand command = - createTestCommand(hasLongOutput: false); + final TestPackageLoopingCommand command = createTestCommand( + hasLongOutput: false, + ); Error? commandError; - final List output = - await runCommand(command, errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCommand( + command, + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - '${_startHeadingColor}Running for package_a...$_endColor', - '${_startHeadingColor}Running for package_b...$_endColor', - '${_startHeadingColor}Running for package_c...$_endColor', - ])); + output, + containsAllInOrder([ + '${_startHeadingColor}Running for package_a...$_endColor', + '${_startHeadingColor}Running for package_b...$_endColor', + '${_startHeadingColor}Running for package_c...$_endColor', + ]), + ); }); test('does not stop looping on exceptions', () async { createFakePackage('package_a', packagesDir); - final RepositoryPackage failingPackage = - createFakePlugin('package_b', packagesDir); + final RepositoryPackage failingPackage = createFakePlugin( + 'package_b', + packagesDir, + ); createFakePackage('package_c', packagesDir); _addResultFile(failingPackage, _ResultFileType.throws); - final TestPackageLoopingCommand command = - createTestCommand(hasLongOutput: false); + final TestPackageLoopingCommand command = createTestCommand( + hasLongOutput: false, + ); Error? commandError; - final List output = - await runCommand(command, errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCommand( + command, + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - '${_startHeadingColor}Running for package_a...$_endColor', - '${_startHeadingColor}Running for package_b...$_endColor', - '${_startHeadingColor}Running for package_c...$_endColor', - ])); + output, + containsAllInOrder([ + '${_startHeadingColor}Running for package_a...$_endColor', + '${_startHeadingColor}Running for package_b...$_endColor', + '${_startHeadingColor}Running for package_c...$_endColor', + ]), + ); }); }); @@ -202,19 +219,19 @@ void main() { createFakePackage('package_a', packagesDir); gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: '')), - ]; + [FakeProcessInfo(MockProcess(stdout: ''))]; - final TestPackageLoopingCommand command = - createTestCommand(hasLongOutput: false); + final TestPackageLoopingCommand command = createTestCommand( + hasLongOutput: false, + ); final List output = await runCommand(command); expect( - output, - containsAllInOrder([ - '${_startHeadingColor}Running for package_a...$_endColor', - ])); + output, + containsAllInOrder([ + '${_startHeadingColor}Running for package_a...$_endColor', + ]), + ); }); test('runs command if any files are not ignored', () async { @@ -222,22 +239,28 @@ void main() { gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' skip/a other skip/b -''')), - ]; +''', + ), + ), + ]; - final TestPackageLoopingCommand command = - createTestCommand(hasLongOutput: false); + final TestPackageLoopingCommand command = createTestCommand( + hasLongOutput: false, + ); final List output = await runCommand(command); expect( - output, - containsAllInOrder([ - '${_startHeadingColor}Running for package_a...$_endColor', - ])); + output, + containsAllInOrder([ + '${_startHeadingColor}Running for package_a...$_endColor', + ]), + ); }); test('skips commands if all files should be ignored', () async { @@ -245,129 +268,169 @@ skip/b gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' skip/a skip/b -''')), - ]; +''', + ), + ), + ]; - final TestPackageLoopingCommand command = - createTestCommand(hasLongOutput: false); + final TestPackageLoopingCommand command = createTestCommand( + hasLongOutput: false, + ); final List output = await runCommand(command); expect( - output, - isNot(containsAllInOrder([ - contains('Running for package_a'), - ]))); + output, + isNot(containsAllInOrder([contains('Running for package_a')])), + ); expect( - output, - containsAllInOrder([ - '${_startSkipColor}SKIPPING ALL PACKAGES: No changed files affect this command$_endColor', - ])); + output, + containsAllInOrder([ + '${_startSkipColor}SKIPPING ALL PACKAGES: No changed files affect this command$_endColor', + ]), + ); }); }); group('package iteration', () { test('includes plugins and packages', () async { - final RepositoryPackage plugin = - createFakePlugin('a_plugin', packagesDir); - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + ); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); final TestPackageLoopingCommand command = createTestCommand(); await runCommand(command); - expect(command.checkedPackages, - unorderedEquals([plugin.path, package.path])); + expect( + command.checkedPackages, + unorderedEquals([plugin.path, package.path]), + ); }); test('includes third_party/packages', () async { - final RepositoryPackage package1 = - createFakePackage('a_package', packagesDir); - final RepositoryPackage package2 = - createFakePackage('another_package', thirdPartyPackagesDir); + final RepositoryPackage package1 = createFakePackage( + 'a_package', + packagesDir, + ); + final RepositoryPackage package2 = createFakePackage( + 'another_package', + thirdPartyPackagesDir, + ); final TestPackageLoopingCommand command = createTestCommand(); await runCommand(command); - expect(command.checkedPackages, - unorderedEquals([package1.path, package2.path])); + expect( + command.checkedPackages, + unorderedEquals([package1.path, package2.path]), + ); }); test('includes all subpackages when requested', () async { - final RepositoryPackage plugin = createFakePlugin('a_plugin', packagesDir, - examples: ['example1', 'example2']); - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + examples: ['example1', 'example2'], + ); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); final RepositoryPackage subPackage = createFakePackage( - 'sub_package', package.directory, - examples: []); + 'sub_package', + package.directory, + examples: [], + ); final TestPackageLoopingCommand command = createTestCommand( - packageLoopingType: PackageLoopingType.includeAllSubpackages); + packageLoopingType: PackageLoopingType.includeAllSubpackages, + ); await runCommand(command); expect( - command.checkedPackages, - unorderedEquals([ - plugin.path, - getExampleDir(plugin).childDirectory('example1').path, - getExampleDir(plugin).childDirectory('example2').path, - package.path, - getExampleDir(package).path, - subPackage.path, - ])); + command.checkedPackages, + unorderedEquals([ + plugin.path, + getExampleDir(plugin).childDirectory('example1').path, + getExampleDir(plugin).childDirectory('example2').path, + package.path, + getExampleDir(package).path, + subPackage.path, + ]), + ); }); test('includes examples when requested', () async { - final RepositoryPackage plugin = createFakePlugin('a_plugin', packagesDir, - examples: ['example1', 'example2']); - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); - final RepositoryPackage subPackage = - createFakePackage('sub_package', package.directory); + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + examples: ['example1', 'example2'], + ); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); + final RepositoryPackage subPackage = createFakePackage( + 'sub_package', + package.directory, + ); final TestPackageLoopingCommand command = createTestCommand( - packageLoopingType: PackageLoopingType.includeExamples); + packageLoopingType: PackageLoopingType.includeExamples, + ); await runCommand(command); expect( - command.checkedPackages, - unorderedEquals([ - plugin.path, - getExampleDir(plugin).childDirectory('example1').path, - getExampleDir(plugin).childDirectory('example2').path, - package.path, - getExampleDir(package).path, - ])); + command.checkedPackages, + unorderedEquals([ + plugin.path, + getExampleDir(plugin).childDirectory('example1').path, + getExampleDir(plugin).childDirectory('example2').path, + package.path, + getExampleDir(package).path, + ]), + ); expect(command.checkedPackages, isNot(contains(subPackage.path))); }); test('excludes subpackages when main package is excluded', () async { final RepositoryPackage excluded = createFakePlugin( - 'a_plugin', packagesDir, - examples: ['example1', 'example2']); - final RepositoryPackage included = - createFakePackage('a_package', packagesDir); - final RepositoryPackage subpackage = - createFakePackage('sub_package', excluded.directory); + 'a_plugin', + packagesDir, + examples: ['example1', 'example2'], + ); + final RepositoryPackage included = createFakePackage( + 'a_package', + packagesDir, + ); + final RepositoryPackage subpackage = createFakePackage( + 'sub_package', + excluded.directory, + ); final TestPackageLoopingCommand command = createTestCommand( - packageLoopingType: PackageLoopingType.includeAllSubpackages); + packageLoopingType: PackageLoopingType.includeAllSubpackages, + ); await runCommand(command, arguments: ['--exclude=a_plugin']); final Iterable examples = excluded.getExamples(); expect( - command.checkedPackages, - unorderedEquals([ - included.path, - getExampleDir(included).path, - ])); + command.checkedPackages, + unorderedEquals([included.path, getExampleDir(included).path]), + ); expect(command.checkedPackages, isNot(contains(excluded.path))); expect(examples.length, 2); - for (final RepositoryPackage example in examples) { + for (final example in examples) { expect(command.checkedPackages, isNot(contains(example.path))); } expect(command.checkedPackages, isNot(contains(subpackage.path))); @@ -375,90 +438,105 @@ skip/b test('excludes examples when main package is excluded', () async { final RepositoryPackage excluded = createFakePlugin( - 'a_plugin', packagesDir, - examples: ['example1', 'example2']); - final RepositoryPackage included = - createFakePackage('a_package', packagesDir); + 'a_plugin', + packagesDir, + examples: ['example1', 'example2'], + ); + final RepositoryPackage included = createFakePackage( + 'a_package', + packagesDir, + ); final TestPackageLoopingCommand command = createTestCommand( - packageLoopingType: PackageLoopingType.includeExamples); + packageLoopingType: PackageLoopingType.includeExamples, + ); await runCommand(command, arguments: ['--exclude=a_plugin']); final Iterable examples = excluded.getExamples(); expect( - command.checkedPackages, - unorderedEquals([ - included.path, - getExampleDir(included).path, - ])); + command.checkedPackages, + unorderedEquals([included.path, getExampleDir(included).path]), + ); expect(command.checkedPackages, isNot(contains(excluded.path))); expect(examples.length, 2); - for (final RepositoryPackage example in examples) { + for (final example in examples) { expect(command.checkedPackages, isNot(contains(example.path))); } }); test('skips unsupported Flutter versions when requested', () async { final RepositoryPackage excluded = createFakePlugin( - 'a_plugin', packagesDir, - flutterConstraint: '>=2.10.0'); - final RepositoryPackage included = - createFakePackage('a_package', packagesDir); + 'a_plugin', + packagesDir, + flutterConstraint: '>=2.10.0', + ); + final RepositoryPackage included = createFakePackage( + 'a_package', + packagesDir, + ); final TestPackageLoopingCommand command = createTestCommand( - packageLoopingType: PackageLoopingType.includeAllSubpackages, - hasLongOutput: false); - final List output = await runCommand(command, arguments: [ - '--skip-if-not-supporting-flutter-version=2.5.0' - ]); - - expect( - command.checkedPackages, - unorderedEquals([ - included.path, - getExampleDir(included).path, - ])); + packageLoopingType: PackageLoopingType.includeAllSubpackages, + hasLongOutput: false, + ); + final List output = await runCommand( + command, + arguments: ['--skip-if-not-supporting-flutter-version=2.5.0'], + ); + + expect( + command.checkedPackages, + unorderedEquals([included.path, getExampleDir(included).path]), + ); expect(command.checkedPackages, isNot(contains(excluded.path))); expect( - output, - containsAllInOrder([ - '${_startHeadingColor}Running for a_package...$_endColor', - '${_startHeadingColor}Running for a_plugin...$_endColor', - '$_startSkipColor SKIPPING: Does not support Flutter 2.5.0$_endColor', - ])); + output, + containsAllInOrder([ + '${_startHeadingColor}Running for a_package...$_endColor', + '${_startHeadingColor}Running for a_plugin...$_endColor', + '$_startSkipColor SKIPPING: Does not support Flutter 2.5.0$_endColor', + ]), + ); }); test('skips unsupported Dart versions when requested', () async { final RepositoryPackage excluded = createFakePackage( - 'excluded_package', packagesDir, - dartConstraint: '>=2.18.0 <4.0.0'); - final RepositoryPackage included = - createFakePackage('a_package', packagesDir); + 'excluded_package', + packagesDir, + dartConstraint: '>=2.18.0 <4.0.0', + ); + final RepositoryPackage included = createFakePackage( + 'a_package', + packagesDir, + ); final TestPackageLoopingCommand command = createTestCommand( - packageLoopingType: PackageLoopingType.includeAllSubpackages, - hasLongOutput: false); - final List output = await runCommand(command, arguments: [ - '--skip-if-not-supporting-flutter-version=3.0.0' // Flutter 3.0.0 -> Dart 2.17.0 - ]); - - expect( - command.checkedPackages, - unorderedEquals([ - included.path, - getExampleDir(included).path, - ])); + packageLoopingType: PackageLoopingType.includeAllSubpackages, + hasLongOutput: false, + ); + final List output = await runCommand( + command, + arguments: [ + '--skip-if-not-supporting-flutter-version=3.0.0', // Flutter 3.0.0 -> Dart 2.17.0 + ], + ); + + expect( + command.checkedPackages, + unorderedEquals([included.path, getExampleDir(included).path]), + ); expect(command.checkedPackages, isNot(contains(excluded.path))); expect( - output, - containsAllInOrder([ - '${_startHeadingColor}Running for a_package...$_endColor', - '${_startHeadingColor}Running for excluded_package...$_endColor', - '$_startSkipColor SKIPPING: Does not support Dart 2.17.0$_endColor', - ])); + output, + containsAllInOrder([ + '${_startHeadingColor}Running for a_package...$_endColor', + '${_startHeadingColor}Running for excluded_package...$_endColor', + '$_startSkipColor SKIPPING: Does not support Dart 2.17.0$_endColor', + ]), + ); }); }); @@ -470,30 +548,33 @@ skip/b final TestPackageLoopingCommand command = createTestCommand(); final List output = await runCommand(command); - const String separator = + const separator = '============================================================'; expect( - output, - containsAllInOrder([ - '$_startHeadingColor\n$separator\n|| Running for package_a\n$separator\n$_endColor', - '$_startHeadingColor\n$separator\n|| Running for package_b\n$separator\n$_endColor', - ])); + output, + containsAllInOrder([ + '$_startHeadingColor\n$separator\n|| Running for package_a\n$separator\n$_endColor', + '$_startHeadingColor\n$separator\n|| Running for package_b\n$separator\n$_endColor', + ]), + ); }); test('has the expected package headers for short-form output', () async { createFakePlugin('package_a', packagesDir); createFakePackage('package_b', packagesDir); - final TestPackageLoopingCommand command = - createTestCommand(hasLongOutput: false); + final TestPackageLoopingCommand command = createTestCommand( + hasLongOutput: false, + ); final List output = await runCommand(command); expect( - output, - containsAllInOrder([ - '${_startHeadingColor}Running for package_a...$_endColor', - '${_startHeadingColor}Running for package_b...$_endColor', - ])); + output, + containsAllInOrder([ + '${_startHeadingColor}Running for package_a...$_endColor', + '${_startHeadingColor}Running for package_b...$_endColor', + ]), + ); }); test('prints timing info in long-form output when requested', () async { @@ -501,36 +582,43 @@ skip/b createFakePackage('package_b', packagesDir); final TestPackageLoopingCommand command = createTestCommand(); - final List output = - await runCommand(command, arguments: ['--log-timing']); + final List output = await runCommand( + command, + arguments: ['--log-timing'], + ); - const String separator = + const separator = '============================================================'; expect( - output, - containsAllInOrder([ - '$_startHeadingColor\n$separator\n|| Running for package_a [@0:00]\n$separator\n$_endColor', - '$_startElapsedTimeColor\n[package_a completed in 0m 0s]$_endColor', - '$_startHeadingColor\n$separator\n|| Running for package_b [@0:00]\n$separator\n$_endColor', - '$_startElapsedTimeColor\n[package_b completed in 0m 0s]$_endColor', - ])); + output, + containsAllInOrder([ + '$_startHeadingColor\n$separator\n|| Running for package_a [@0:00]\n$separator\n$_endColor', + '$_startElapsedTimeColor\n[package_a completed in 0m 0s]$_endColor', + '$_startHeadingColor\n$separator\n|| Running for package_b [@0:00]\n$separator\n$_endColor', + '$_startElapsedTimeColor\n[package_b completed in 0m 0s]$_endColor', + ]), + ); }); test('prints timing info in short-form output when requested', () async { createFakePlugin('package_a', packagesDir); createFakePackage('package_b', packagesDir); - final TestPackageLoopingCommand command = - createTestCommand(hasLongOutput: false); - final List output = - await runCommand(command, arguments: ['--log-timing']); + final TestPackageLoopingCommand command = createTestCommand( + hasLongOutput: false, + ); + final List output = await runCommand( + command, + arguments: ['--log-timing'], + ); expect( - output, - containsAllInOrder([ - '$_startHeadingColor[0:00] Running for package_a...$_endColor', - '$_startHeadingColor[0:00] Running for package_b...$_endColor', - ])); + output, + containsAllInOrder([ + '$_startHeadingColor[0:00] Running for package_a...$_endColor', + '$_startHeadingColor[0:00] Running for package_b...$_endColor', + ]), + ); // Short-form output should not include elapsed time. expect(output, isNot(contains('[package_a completed in 0m 0s]'))); }); @@ -539,39 +627,49 @@ skip/b createFakePackage('package_a', packagesDir); createFakePackage('package_b', packagesDir); - final TestPackageLoopingCommand command = - createTestCommand(hasLongOutput: false); + final TestPackageLoopingCommand command = createTestCommand( + hasLongOutput: false, + ); final List output = await runCommand(command); expect( - output, - containsAllInOrder([ - '\n', - '${_startSuccessColor}No issues found!$_endColor', - ])); + output, + containsAllInOrder([ + '\n', + '${_startSuccessColor}No issues found!$_endColor', + ]), + ); }); - test('shows failure summaries when something fails without extra details', - () async { - createFakePackage('package_a', packagesDir); - final RepositoryPackage failingPackage1 = - createFakePlugin('package_b', packagesDir); - createFakePackage('package_c', packagesDir); - final RepositoryPackage failingPackage2 = - createFakePlugin('package_d', packagesDir); - _addResultFile(failingPackage1, _ResultFileType.errors); - _addResultFile(failingPackage2, _ResultFileType.errors); - - final TestPackageLoopingCommand command = - createTestCommand(hasLongOutput: false); - Error? commandError; - final List output = - await runCommand(command, errorHandler: (Error e) { - commandError = e; - }); - - expect(commandError, isA()); - expect( + test( + 'shows failure summaries when something fails without extra details', + () async { + createFakePackage('package_a', packagesDir); + final RepositoryPackage failingPackage1 = createFakePlugin( + 'package_b', + packagesDir, + ); + createFakePackage('package_c', packagesDir); + final RepositoryPackage failingPackage2 = createFakePlugin( + 'package_d', + packagesDir, + ); + _addResultFile(failingPackage1, _ResultFileType.errors); + _addResultFile(failingPackage2, _ResultFileType.errors); + + final TestPackageLoopingCommand command = createTestCommand( + hasLongOutput: false, + ); + Error? commandError; + final List output = await runCommand( + command, + errorHandler: (Error e) { + commandError = e; + }, + ); + + expect(commandError, isA()); + expect( output, containsAllInOrder([ '\n', @@ -579,64 +677,88 @@ skip/b '$_startErrorColor package_b$_endColor', '$_startErrorColor package_d$_endColor', '${_startErrorColor}See above for full details.$_endColor', - ])); - }); + ]), + ); + }, + ); test('uses custom summary header and footer if provided', () async { createFakePackage('package_a', packagesDir); - final RepositoryPackage failingPackage1 = - createFakePlugin('package_b', packagesDir); + final RepositoryPackage failingPackage1 = createFakePlugin( + 'package_b', + packagesDir, + ); createFakePackage('package_c', packagesDir); - final RepositoryPackage failingPackage2 = - createFakePlugin('package_d', packagesDir); + final RepositoryPackage failingPackage2 = createFakePlugin( + 'package_d', + packagesDir, + ); _addResultFile(failingPackage1, _ResultFileType.errors); _addResultFile(failingPackage2, _ResultFileType.errors); final TestPackageLoopingCommand command = createTestCommand( - hasLongOutput: false, - customFailureListHeader: 'This is a custom header', - customFailureListFooter: 'And a custom footer!'); + hasLongOutput: false, + customFailureListHeader: 'This is a custom header', + customFailureListFooter: 'And a custom footer!', + ); Error? commandError; - final List output = - await runCommand(command, errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCommand( + command, + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - '\n', - '${_startErrorColor}This is a custom header$_endColor', - '$_startErrorColor package_b$_endColor', - '$_startErrorColor package_d$_endColor', - '${_startErrorColor}And a custom footer!$_endColor', - ])); + output, + containsAllInOrder([ + '\n', + '${_startErrorColor}This is a custom header$_endColor', + '$_startErrorColor package_b$_endColor', + '$_startErrorColor package_d$_endColor', + '${_startErrorColor}And a custom footer!$_endColor', + ]), + ); }); - test('shows failure summaries when something fails with extra details', - () async { - createFakePackage('package_a', packagesDir); - final RepositoryPackage failingPackage1 = - createFakePlugin('package_b', packagesDir); - createFakePackage('package_c', packagesDir); - final RepositoryPackage failingPackage2 = - createFakePlugin('package_d', packagesDir); - _addResultFile(failingPackage1, _ResultFileType.errors, - contents: 'just one detail'); - _addResultFile(failingPackage2, _ResultFileType.errors, - contents: 'first detail\nsecond detail'); - - final TestPackageLoopingCommand command = - createTestCommand(hasLongOutput: false); - Error? commandError; - final List output = - await runCommand(command, errorHandler: (Error e) { - commandError = e; - }); - - expect(commandError, isA()); - expect( + test( + 'shows failure summaries when something fails with extra details', + () async { + createFakePackage('package_a', packagesDir); + final RepositoryPackage failingPackage1 = createFakePlugin( + 'package_b', + packagesDir, + ); + createFakePackage('package_c', packagesDir); + final RepositoryPackage failingPackage2 = createFakePlugin( + 'package_d', + packagesDir, + ); + _addResultFile( + failingPackage1, + _ResultFileType.errors, + contents: 'just one detail', + ); + _addResultFile( + failingPackage2, + _ResultFileType.errors, + contents: 'first detail\nsecond detail', + ); + + final TestPackageLoopingCommand command = createTestCommand( + hasLongOutput: false, + ); + Error? commandError; + final List output = await runCommand( + command, + errorHandler: (Error e) { + commandError = e; + }, + ); + + expect(commandError, isA()); + expect( output, containsAllInOrder([ '\n', @@ -644,154 +766,207 @@ skip/b '$_startErrorColor package_b:\n just one detail$_endColor', '$_startErrorColor package_d:\n first detail\n second detail$_endColor', '${_startErrorColor}See above for full details.$_endColor', - ])); - }); + ]), + ); + }, + ); test('is captured, not printed, when requested', () async { createFakePlugin('package_a', packagesDir); createFakePackage('package_b', packagesDir); - final TestPackageLoopingCommand command = - createTestCommand(captureOutput: true); + final TestPackageLoopingCommand command = createTestCommand( + captureOutput: true, + ); final List output = await runCommand(command); expect(output, isEmpty); // None of the output should be colorized when captured. - const String separator = + const separator = '============================================================'; expect( - command.capturedOutput, - containsAllInOrder([ - '\n$separator\n|| Running for package_a\n$separator\n', - '\n$separator\n|| Running for package_b\n$separator\n', - 'No issues found!', - ])); + command.capturedOutput, + containsAllInOrder([ + '\n$separator\n|| Running for package_a\n$separator\n', + '\n$separator\n|| Running for package_b\n$separator\n', + 'No issues found!', + ]), + ); }); test('logs skips', () async { createFakePackage('package_a', packagesDir); - final RepositoryPackage skipPackage = - createFakePackage('package_b', packagesDir); - _addResultFile(skipPackage, _ResultFileType.skips, - contents: 'For a reason'); + final RepositoryPackage skipPackage = createFakePackage( + 'package_b', + packagesDir, + ); + _addResultFile( + skipPackage, + _ResultFileType.skips, + contents: 'For a reason', + ); - final TestPackageLoopingCommand command = - createTestCommand(hasLongOutput: false); + final TestPackageLoopingCommand command = createTestCommand( + hasLongOutput: false, + ); final List output = await runCommand(command); expect( - output, - containsAllInOrder([ - '${_startHeadingColor}Running for package_a...$_endColor', - '${_startHeadingColor}Running for package_b...$_endColor', - '$_startSkipColor SKIPPING: For a reason$_endColor', - ])); + output, + containsAllInOrder([ + '${_startHeadingColor}Running for package_a...$_endColor', + '${_startHeadingColor}Running for package_b...$_endColor', + '$_startSkipColor SKIPPING: For a reason$_endColor', + ]), + ); }); test('logs exclusions', () async { createFakePackage('package_a', packagesDir); createFakePackage('package_b', packagesDir); - final TestPackageLoopingCommand command = - createTestCommand(hasLongOutput: false); - final List output = - await runCommand(command, arguments: ['--exclude=package_b']); + final TestPackageLoopingCommand command = createTestCommand( + hasLongOutput: false, + ); + final List output = await runCommand( + command, + arguments: ['--exclude=package_b'], + ); expect( - output, - containsAllInOrder([ - '${_startHeadingColor}Running for package_a...$_endColor', - '${_startSkipColor}Not running for package_b; excluded$_endColor', - ])); + output, + containsAllInOrder([ + '${_startHeadingColor}Running for package_a...$_endColor', + '${_startSkipColor}Not running for package_b; excluded$_endColor', + ]), + ); }); test('logs warnings', () async { - final RepositoryPackage warnPackage = - createFakePackage('package_a', packagesDir); - _addResultFile(warnPackage, _ResultFileType.warns, - contents: 'Warning 1\nWarning 2'); + final RepositoryPackage warnPackage = createFakePackage( + 'package_a', + packagesDir, + ); + _addResultFile( + warnPackage, + _ResultFileType.warns, + contents: 'Warning 1\nWarning 2', + ); createFakePackage('package_b', packagesDir); - final TestPackageLoopingCommand command = - createTestCommand(hasLongOutput: false); + final TestPackageLoopingCommand command = createTestCommand( + hasLongOutput: false, + ); final List output = await runCommand(command); expect( - output, - containsAllInOrder([ - '${_startHeadingColor}Running for package_a...$_endColor', - '${_startWarningColor}Warning 1$_endColor', - '${_startWarningColor}Warning 2$_endColor', - '${_startHeadingColor}Running for package_b...$_endColor', - ])); + output, + containsAllInOrder([ + '${_startHeadingColor}Running for package_a...$_endColor', + '${_startWarningColor}Warning 1$_endColor', + '${_startWarningColor}Warning 2$_endColor', + '${_startHeadingColor}Running for package_b...$_endColor', + ]), + ); }); test('logs unhandled exceptions as errors', () async { createFakePackage('package_a', packagesDir); - final RepositoryPackage failingPackage = - createFakePlugin('package_b', packagesDir); + final RepositoryPackage failingPackage = createFakePlugin( + 'package_b', + packagesDir, + ); createFakePackage('package_c', packagesDir); _addResultFile(failingPackage, _ResultFileType.throws); - final TestPackageLoopingCommand command = - createTestCommand(hasLongOutput: false); + final TestPackageLoopingCommand command = createTestCommand( + hasLongOutput: false, + ); Error? commandError; - final List output = - await runCommand(command, errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCommand( + command, + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - '${_startErrorColor}Exception: Uh-oh$_endColor', - '${_startErrorColor}The following packages had errors:$_endColor', - '$_startErrorColor package_b:\n Unhandled exception$_endColor', - ])); + output, + containsAllInOrder([ + '${_startErrorColor}Exception: Uh-oh$_endColor', + '${_startErrorColor}The following packages had errors:$_endColor', + '$_startErrorColor package_b:\n Unhandled exception$_endColor', + ]), + ); }); test('prints run summary on success', () async { - final RepositoryPackage warnPackage1 = - createFakePackage('package_a', packagesDir); - _addResultFile(warnPackage1, _ResultFileType.warns, - contents: 'Warning 1\nWarning 2'); + final RepositoryPackage warnPackage1 = createFakePackage( + 'package_a', + packagesDir, + ); + _addResultFile( + warnPackage1, + _ResultFileType.warns, + contents: 'Warning 1\nWarning 2', + ); createFakePackage('package_b', packagesDir); - final RepositoryPackage skipPackage = - createFakePackage('package_c', packagesDir); - _addResultFile(skipPackage, _ResultFileType.skips, - contents: 'For a reason'); + final RepositoryPackage skipPackage = createFakePackage( + 'package_c', + packagesDir, + ); + _addResultFile( + skipPackage, + _ResultFileType.skips, + contents: 'For a reason', + ); - final RepositoryPackage skipAndWarnPackage = - createFakePackage('package_d', packagesDir); - _addResultFile(skipAndWarnPackage, _ResultFileType.warns, - contents: 'Warning'); - _addResultFile(skipAndWarnPackage, _ResultFileType.skips, - contents: 'See warning'); + final RepositoryPackage skipAndWarnPackage = createFakePackage( + 'package_d', + packagesDir, + ); + _addResultFile( + skipAndWarnPackage, + _ResultFileType.warns, + contents: 'Warning', + ); + _addResultFile( + skipAndWarnPackage, + _ResultFileType.skips, + contents: 'See warning', + ); - final RepositoryPackage warnPackage2 = - createFakePackage('package_e', packagesDir); - _addResultFile(warnPackage2, _ResultFileType.warns, - contents: 'Warning 1\nWarning 2'); + final RepositoryPackage warnPackage2 = createFakePackage( + 'package_e', + packagesDir, + ); + _addResultFile( + warnPackage2, + _ResultFileType.warns, + contents: 'Warning 1\nWarning 2', + ); createFakePackage('package_f', packagesDir); - final TestPackageLoopingCommand command = - createTestCommand(hasLongOutput: false); + final TestPackageLoopingCommand command = createTestCommand( + hasLongOutput: false, + ); final List output = await runCommand(command); expect( - output, - containsAllInOrder([ - '------------------------------------------------------------', - 'Ran for 4 package(s) (2 with warnings)', - 'Skipped 2 package(s) (1 with warnings)', - '\n', - '${_startSuccessColor}No issues found!$_endColor', - ])); + output, + containsAllInOrder([ + '------------------------------------------------------------', + 'Ran for 4 package(s) (2 with warnings)', + 'Skipped 2 package(s) (1 with warnings)', + '\n', + '${_startSuccessColor}No issues found!$_endColor', + ]), + ); // The long-form summary should not be printed for short-form commands. expect(output, isNot(contains('Run summary:'))); expect(output, isNot(contains(contains('package a - ran')))); @@ -800,45 +975,72 @@ skip/b test('counts exclusions as skips in run summary', () async { createFakePackage('package_a', packagesDir); - final TestPackageLoopingCommand command = - createTestCommand(hasLongOutput: false); - final List output = - await runCommand(command, arguments: ['--exclude=package_a']); + final TestPackageLoopingCommand command = createTestCommand( + hasLongOutput: false, + ); + final List output = await runCommand( + command, + arguments: ['--exclude=package_a'], + ); expect( - output, - containsAllInOrder([ - '------------------------------------------------------------', - 'Skipped 1 package(s)', - '\n', - '${_startSuccessColor}No issues found!$_endColor', - ])); + output, + containsAllInOrder([ + '------------------------------------------------------------', + 'Skipped 1 package(s)', + '\n', + '${_startSuccessColor}No issues found!$_endColor', + ]), + ); }); test('prints long-form run summary for long-output commands', () async { - final RepositoryPackage warnPackage1 = - createFakePackage('package_a', packagesDir); - _addResultFile(warnPackage1, _ResultFileType.warns, - contents: 'Warning 1\nWarning 2'); + final RepositoryPackage warnPackage1 = createFakePackage( + 'package_a', + packagesDir, + ); + _addResultFile( + warnPackage1, + _ResultFileType.warns, + contents: 'Warning 1\nWarning 2', + ); createFakePackage('package_b', packagesDir); - final RepositoryPackage skipPackage = - createFakePackage('package_c', packagesDir); - _addResultFile(skipPackage, _ResultFileType.skips, - contents: 'For a reason'); + final RepositoryPackage skipPackage = createFakePackage( + 'package_c', + packagesDir, + ); + _addResultFile( + skipPackage, + _ResultFileType.skips, + contents: 'For a reason', + ); - final RepositoryPackage skipAndWarnPackage = - createFakePackage('package_d', packagesDir); - _addResultFile(skipAndWarnPackage, _ResultFileType.warns, - contents: 'Warning'); - _addResultFile(skipAndWarnPackage, _ResultFileType.skips, - contents: 'See warning'); + final RepositoryPackage skipAndWarnPackage = createFakePackage( + 'package_d', + packagesDir, + ); + _addResultFile( + skipAndWarnPackage, + _ResultFileType.warns, + contents: 'Warning', + ); + _addResultFile( + skipAndWarnPackage, + _ResultFileType.skips, + contents: 'See warning', + ); - final RepositoryPackage warnPackage2 = - createFakePackage('package_e', packagesDir); - _addResultFile(warnPackage2, _ResultFileType.warns, - contents: 'Warning 1\nWarning 2'); + final RepositoryPackage warnPackage2 = createFakePackage( + 'package_e', + packagesDir, + ); + _addResultFile( + warnPackage2, + _ResultFileType.warns, + contents: 'Warning 1\nWarning 2', + ); createFakePackage('package_f', packagesDir); @@ -846,40 +1048,44 @@ skip/b final List output = await runCommand(command); expect( - output, - containsAllInOrder([ - '------------------------------------------------------------', - 'Run overview:', - ' package_a - ${_startWarningColor}ran (with warning)$_endColor', - ' package_b - ${_startSuccessColor}ran$_endColor', - ' package_c - ${_startSkipColor}skipped$_endColor', - ' package_d - ${_startSkipWithWarningColor}skipped (with warning)$_endColor', - ' package_e - ${_startWarningColor}ran (with warning)$_endColor', - ' package_f - ${_startSuccessColor}ran$_endColor', - '', - 'Ran for 4 package(s) (2 with warnings)', - 'Skipped 2 package(s) (1 with warnings)', - '\n', - '${_startSuccessColor}No issues found!$_endColor', - ])); + output, + containsAllInOrder([ + '------------------------------------------------------------', + 'Run overview:', + ' package_a - ${_startWarningColor}ran (with warning)$_endColor', + ' package_b - ${_startSuccessColor}ran$_endColor', + ' package_c - ${_startSkipColor}skipped$_endColor', + ' package_d - ${_startSkipWithWarningColor}skipped (with warning)$_endColor', + ' package_e - ${_startWarningColor}ran (with warning)$_endColor', + ' package_f - ${_startSuccessColor}ran$_endColor', + '', + 'Ran for 4 package(s) (2 with warnings)', + 'Skipped 2 package(s) (1 with warnings)', + '\n', + '${_startSuccessColor}No issues found!$_endColor', + ]), + ); }); test('prints exclusions as skips in long-form run summary', () async { createFakePackage('package_a', packagesDir); final TestPackageLoopingCommand command = createTestCommand(); - final List output = - await runCommand(command, arguments: ['--exclude=package_a']); + final List output = await runCommand( + command, + arguments: ['--exclude=package_a'], + ); expect( - output, - containsAllInOrder([ - ' package_a - ${_startSkipColor}excluded$_endColor', - '', - 'Skipped 1 package(s)', - '\n', - '${_startSuccessColor}No issues found!$_endColor', - ])); + output, + containsAllInOrder([ + ' package_a - ${_startSkipColor}excluded$_endColor', + '', + 'Skipped 1 package(s)', + '\n', + '${_startSuccessColor}No issues found!$_endColor', + ]), + ); }); test('handles warnings outside of runForPackage', () async { @@ -892,17 +1098,18 @@ skip/b final List output = await runCommand(command); expect( - output, - containsAllInOrder([ - '${_startWarningColor}Warning during initializeRun$_endColor', - '${_startHeadingColor}Running for package_a...$_endColor', - '${_startWarningColor}Warning during completeRun$_endColor', - '------------------------------------------------------------', - 'Ran for 1 package(s)', - '2 warnings not associated with a package', - '\n', - '${_startSuccessColor}No issues found!$_endColor', - ])); + output, + containsAllInOrder([ + '${_startWarningColor}Warning during initializeRun$_endColor', + '${_startHeadingColor}Running for package_a...$_endColor', + '${_startWarningColor}Warning during completeRun$_endColor', + '------------------------------------------------------------', + 'Ran for 1 package(s)', + '2 warnings not associated with a package', + '\n', + '${_startSuccessColor}No issues found!$_endColor', + ]), + ); }); }); } diff --git a/script/tool/test/common/package_state_utils_test.dart b/script/tool/test/common/package_state_utils_test.dart index 7ec4089dbe05..6bf145bc6705 100644 --- a/script/tool/test/common/package_state_utils_test.dart +++ b/script/tool/test/common/package_state_utils_test.dart @@ -19,16 +19,18 @@ void main() { group('checkPackageChangeState', () { test('reports version change needed for code changes', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); - const List changedFiles = [ - 'packages/a_package/lib/plugin.dart', - ]; + const changedFiles = ['packages/a_package/lib/plugin.dart']; - final PackageChangeState state = await checkPackageChangeState(package, - changedPaths: changedFiles, - relativePackagePath: 'packages/a_package'); + final PackageChangeState state = await checkPackageChangeState( + package, + changedPaths: changedFiles, + relativePackagePath: 'packages/a_package', + ); expect(state.hasChanges, true); expect(state.needsVersionChange, true); @@ -36,16 +38,18 @@ void main() { }); test('handles trailing slash on package path', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); - const List changedFiles = [ - 'packages/a_package/lib/plugin.dart', - ]; + const changedFiles = ['packages/a_package/lib/plugin.dart']; - final PackageChangeState state = await checkPackageChangeState(package, - changedPaths: changedFiles, - relativePackagePath: 'packages/a_package/'); + final PackageChangeState state = await checkPackageChangeState( + package, + changedPaths: changedFiles, + relativePackagePath: 'packages/a_package/', + ); expect(state.hasChanges, true); expect(state.needsVersionChange, true); @@ -53,12 +57,13 @@ void main() { expect(state.hasChangelogChange, false); }); - test('does not flag version- and changelog-change-exempt changes', - () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir); + test('does not flag version- and changelog-change-exempt changes', () async { + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + ); - const List changedFiles = [ + const changedFiles = [ 'packages/a_plugin/CHANGELOG.md', // Dev-facing docs. 'packages/a_plugin/CONTRIBUTING.md', @@ -91,9 +96,11 @@ void main() { 'packages/a_plugin/platform_tests/test_plugin/windows/test_plugin.cpp', ]; - final PackageChangeState state = await checkPackageChangeState(package, - changedPaths: changedFiles, - relativePackagePath: 'packages/a_plugin/'); + final PackageChangeState state = await checkPackageChangeState( + package, + changedPaths: changedFiles, + relativePackagePath: 'packages/a_plugin/', + ); expect(state.hasChanges, true); expect(state.needsVersionChange, false); @@ -102,16 +109,20 @@ void main() { }); test('only considers a root "tool" folder to be special', () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir); + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + ); - const List changedFiles = [ + const changedFiles = [ 'packages/a_plugin/lib/foo/tool/tool_thing.dart', ]; - final PackageChangeState state = await checkPackageChangeState(package, - changedPaths: changedFiles, - relativePackagePath: 'packages/a_plugin/'); + final PackageChangeState state = await checkPackageChangeState( + package, + changedPaths: changedFiles, + relativePackagePath: 'packages/a_plugin/', + ); expect(state.hasChanges, true); expect(state.needsVersionChange, true); @@ -120,16 +131,18 @@ void main() { test('requires a version change for example/lib/main.dart', () async { final RepositoryPackage package = createFakePlugin( - 'a_plugin', packagesDir, - extraFiles: ['example/lib/main.dart']); + 'a_plugin', + packagesDir, + extraFiles: ['example/lib/main.dart'], + ); - const List changedFiles = [ - 'packages/a_plugin/example/lib/main.dart', - ]; + const changedFiles = ['packages/a_plugin/example/lib/main.dart']; - final PackageChangeState state = await checkPackageChangeState(package, - changedPaths: changedFiles, - relativePackagePath: 'packages/a_plugin/'); + final PackageChangeState state = await checkPackageChangeState( + package, + changedPaths: changedFiles, + relativePackagePath: 'packages/a_plugin/', + ); expect(state.hasChanges, true); expect(state.needsVersionChange, true); @@ -138,16 +151,18 @@ void main() { test('requires a version change for example/main.dart', () async { final RepositoryPackage package = createFakePlugin( - 'a_plugin', packagesDir, - extraFiles: ['example/main.dart']); + 'a_plugin', + packagesDir, + extraFiles: ['example/main.dart'], + ); - const List changedFiles = [ - 'packages/a_plugin/example/main.dart', - ]; + const changedFiles = ['packages/a_plugin/example/main.dart']; - final PackageChangeState state = await checkPackageChangeState(package, - changedPaths: changedFiles, - relativePackagePath: 'packages/a_plugin/'); + final PackageChangeState state = await checkPackageChangeState( + package, + changedPaths: changedFiles, + relativePackagePath: 'packages/a_plugin/', + ); expect(state.hasChanges, true); expect(state.needsVersionChange, true); @@ -155,16 +170,18 @@ void main() { }); test('requires a version change for example readme.md', () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir); + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + ); - const List changedFiles = [ - 'packages/a_plugin/example/README.md', - ]; + const changedFiles = ['packages/a_plugin/example/README.md']; - final PackageChangeState state = await checkPackageChangeState(package, - changedPaths: changedFiles, - relativePackagePath: 'packages/a_plugin/'); + final PackageChangeState state = await checkPackageChangeState( + package, + changedPaths: changedFiles, + relativePackagePath: 'packages/a_plugin/', + ); expect(state.hasChanges, true); expect(state.needsVersionChange, true); @@ -173,58 +190,64 @@ void main() { test('requires a version change for example/example.md', () async { final RepositoryPackage package = createFakePlugin( - 'a_plugin', packagesDir, - extraFiles: ['example/example.md']); + 'a_plugin', + packagesDir, + extraFiles: ['example/example.md'], + ); - const List changedFiles = [ - 'packages/a_plugin/example/example.md', - ]; + const changedFiles = ['packages/a_plugin/example/example.md']; - final PackageChangeState state = await checkPackageChangeState(package, - changedPaths: changedFiles, - relativePackagePath: 'packages/a_plugin/'); + final PackageChangeState state = await checkPackageChangeState( + package, + changedPaths: changedFiles, + relativePackagePath: 'packages/a_plugin/', + ); expect(state.hasChanges, true); expect(state.needsVersionChange, true); expect(state.needsChangelogChange, true); }); - test( - 'requires a changelog change but no version change for ' + test('requires a changelog change but no version change for ' 'lower-priority examples when example.md is present', () async { final RepositoryPackage package = createFakePlugin( - 'a_plugin', packagesDir, - extraFiles: ['example/example.md']); + 'a_plugin', + packagesDir, + extraFiles: ['example/example.md'], + ); - const List changedFiles = [ + const changedFiles = [ 'packages/a_plugin/example/lib/main.dart', 'packages/a_plugin/example/main.dart', 'packages/a_plugin/example/README.md', ]; - final PackageChangeState state = await checkPackageChangeState(package, - changedPaths: changedFiles, - relativePackagePath: 'packages/a_plugin/'); + final PackageChangeState state = await checkPackageChangeState( + package, + changedPaths: changedFiles, + relativePackagePath: 'packages/a_plugin/', + ); expect(state.hasChanges, true); expect(state.needsVersionChange, false); expect(state.needsChangelogChange, true); }); - test( - 'requires a changelog change but no version change for README.md when ' + test('requires a changelog change but no version change for README.md when ' 'code example is present', () async { final RepositoryPackage package = createFakePlugin( - 'a_plugin', packagesDir, - extraFiles: ['example/lib/main.dart']); + 'a_plugin', + packagesDir, + extraFiles: ['example/lib/main.dart'], + ); - const List changedFiles = [ - 'packages/a_plugin/example/README.md', - ]; + const changedFiles = ['packages/a_plugin/example/README.md']; - final PackageChangeState state = await checkPackageChangeState(package, - changedPaths: changedFiles, - relativePackagePath: 'packages/a_plugin/'); + final PackageChangeState state = await checkPackageChangeState( + package, + changedPaths: changedFiles, + relativePackagePath: 'packages/a_plugin/', + ); expect(state.hasChanges, true); expect(state.needsVersionChange, false); @@ -232,35 +255,39 @@ void main() { }); test( - 'requires neither a changelog nor version change for README.md when ' - 'code example is present in a federated plugin implementation', - () async { - final RepositoryPackage package = createFakePlugin( - 'a_plugin_android', packagesDir.childDirectory('a_plugin'), - extraFiles: ['example/lib/main.dart']); - - const List changedFiles = [ - 'packages/a_plugin/a_plugin_android/example/README.md', - ]; - - final PackageChangeState state = await checkPackageChangeState(package, + 'requires neither a changelog nor version change for README.md when ' + 'code example is present in a federated plugin implementation', + () async { + final RepositoryPackage package = createFakePlugin( + 'a_plugin_android', + packagesDir.childDirectory('a_plugin'), + extraFiles: ['example/lib/main.dart'], + ); + + const changedFiles = [ + 'packages/a_plugin/a_plugin_android/example/README.md', + ]; + + final PackageChangeState state = await checkPackageChangeState( + package, changedPaths: changedFiles, - relativePackagePath: 'packages/a_plugin/a_plugin_android'); + relativePackagePath: 'packages/a_plugin/a_plugin_android', + ); - expect(state.hasChanges, true); - expect(state.needsVersionChange, false); - expect(state.needsChangelogChange, false); - }); + expect(state.hasChanges, true); + expect(state.needsVersionChange, false); + expect(state.needsChangelogChange, false); + }, + ); - test( - 'does not requires changelog or version change for build.gradle ' + test('does not requires changelog or version change for build.gradle ' 'test-dependency-only changes with space style', () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir); + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + ); - const List changedFiles = [ - 'packages/a_plugin/android/build.gradle', - ]; + const changedFiles = ['packages/a_plugin/android/build.gradle']; final GitVersionFinder git = FakeGitVersionFinder(>{ 'packages/a_plugin/android/build.gradle': [ @@ -268,28 +295,29 @@ void main() { "- testImplementation 'junit:junit:4.10.0'", "+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'", "+ testImplementation 'junit:junit:4.13.2'", - ] + ], }); - final PackageChangeState state = await checkPackageChangeState(package, - changedPaths: changedFiles, - relativePackagePath: 'packages/a_plugin/', - git: git); + final PackageChangeState state = await checkPackageChangeState( + package, + changedPaths: changedFiles, + relativePackagePath: 'packages/a_plugin/', + git: git, + ); expect(state.hasChanges, true); expect(state.needsVersionChange, false); expect(state.needsChangelogChange, false); }); - test( - 'does not require changelog or version change for build.gradle ' + test('does not require changelog or version change for build.gradle ' 'test-dependency-only changes with paren style', () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir); + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + ); - const List changedFiles = [ - 'packages/a_plugin/android/build.gradle', - ]; + const changedFiles = ['packages/a_plugin/android/build.gradle']; final GitVersionFinder git = FakeGitVersionFinder(>{ 'packages/a_plugin/android/build.gradle': [ @@ -297,13 +325,15 @@ void main() { '- testImplementation("junit:junit:4.10.0")', '+ androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")', '+ testImplementation("junit:junit:4.13.2")', - ] + ], }); - final PackageChangeState state = await checkPackageChangeState(package, - changedPaths: changedFiles, - relativePackagePath: 'packages/a_plugin/', - git: git); + final PackageChangeState state = await checkPackageChangeState( + package, + changedPaths: changedFiles, + relativePackagePath: 'packages/a_plugin/', + git: git, + ); expect(state.hasChanges, true); expect(state.needsVersionChange, false); @@ -311,109 +341,90 @@ void main() { }); test( - 'requires changelog or version change for other build.gradle changes with space style', - () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir); - - const List changedFiles = [ - 'packages/a_plugin/android/build.gradle', - ]; - - final GitVersionFinder git = FakeGitVersionFinder(>{ - 'packages/a_plugin/android/build.gradle': [ - "- androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'", - "- testImplementation 'junit:junit:4.10.0'", - "+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'", - "+ testImplementation 'junit:junit:4.13.2'", - "- implementation 'com.google.android.gms:play-services-maps:18.0.0'", - "+ implementation 'com.google.android.gms:play-services-maps:18.0.2'", - ] - }); - - final PackageChangeState state = await checkPackageChangeState(package, + 'requires changelog or version change for other build.gradle changes with space style', + () async { + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + ); + + const changedFiles = ['packages/a_plugin/android/build.gradle']; + + final GitVersionFinder + git = FakeGitVersionFinder(>{ + 'packages/a_plugin/android/build.gradle': [ + "- androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'", + "- testImplementation 'junit:junit:4.10.0'", + "+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'", + "+ testImplementation 'junit:junit:4.13.2'", + "- implementation 'com.google.android.gms:play-services-maps:18.0.0'", + "+ implementation 'com.google.android.gms:play-services-maps:18.0.2'", + ], + }); + + final PackageChangeState state = await checkPackageChangeState( + package, changedPaths: changedFiles, relativePackagePath: 'packages/a_plugin/', - git: git); + git: git, + ); - expect(state.hasChanges, true); - expect(state.needsVersionChange, true); - expect(state.needsChangelogChange, true); - }); + expect(state.hasChanges, true); + expect(state.needsVersionChange, true); + expect(state.needsChangelogChange, true); + }, + ); test( - 'requires changelog or version change for other build.gradle changes with paren style', - () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir); - - const List changedFiles = [ - 'packages/a_plugin/android/build.gradle', - ]; - - final GitVersionFinder git = FakeGitVersionFinder(>{ - 'packages/a_plugin/android/build.gradle': [ - '- androidTestImplementation("androidx.test.espresso:espresso-core:3.2.0")', - '- testImplementation("junit:junit:4.10.0")', - '+ androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")', - '+ testImplementation("junit:junit:4.13.2")', - '- implementation("com.google.android.gms:play-services-maps:18.0.0")', - '+ implementation("com.google.android.gms:play-services-maps:18.0.2")', - ] - }); - - final PackageChangeState state = await checkPackageChangeState(package, + 'requires changelog or version change for other build.gradle changes with paren style', + () async { + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + ); + + const changedFiles = ['packages/a_plugin/android/build.gradle']; + + final GitVersionFinder + git = FakeGitVersionFinder(>{ + 'packages/a_plugin/android/build.gradle': [ + '- androidTestImplementation("androidx.test.espresso:espresso-core:3.2.0")', + '- testImplementation("junit:junit:4.10.0")', + '+ androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")', + '+ testImplementation("junit:junit:4.13.2")', + '- implementation("com.google.android.gms:play-services-maps:18.0.0")', + '+ implementation("com.google.android.gms:play-services-maps:18.0.2")', + ], + }); + + final PackageChangeState state = await checkPackageChangeState( + package, changedPaths: changedFiles, relativePackagePath: 'packages/a_plugin/', - git: git); + git: git, + ); - expect(state.hasChanges, true); - expect(state.needsVersionChange, true); - expect(state.needsChangelogChange, true); - }); + expect(state.hasChanges, true); + expect(state.needsVersionChange, true); + expect(state.needsChangelogChange, true); + }, + ); - test( - 'does not requires changelog or version change for ' + test('does not requires changelog or version change for ' 'non-doc-comment-only changes', () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir); + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + ); - const List changedFiles = [ - 'packages/a_plugin/lib/a_plugin.dart', - ]; + const changedFiles = ['packages/a_plugin/lib/a_plugin.dart']; final GitVersionFinder git = FakeGitVersionFinder(>{ 'packages/a_plugin/lib/a_plugin.dart': [ '- // Old comment.', '+ // New comment.', '+ ', // Allow whitespace line changes as part of comment changes. - ] - }); - - final PackageChangeState state = await checkPackageChangeState(package, - changedPaths: changedFiles, - relativePackagePath: 'packages/a_plugin/', - git: git); - - expect(state.hasChanges, true); - expect(state.needsVersionChange, false); - expect(state.needsChangelogChange, false); - }); - - test('requires changelog or version change for doc comment changes', - () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir); - - const List changedFiles = [ - 'packages/a_plugin/lib/a_plugin.dart', - ]; - - final GitVersionFinder git = FakeGitVersionFinder(>{ - 'packages/a_plugin/lib/a_plugin.dart': [ - '- /// Old doc comment.', - '+ /// New doc comment.', - ] + ], }); final PackageChangeState state = await checkPackageChangeState( @@ -424,17 +435,49 @@ void main() { ); expect(state.hasChanges, true); - expect(state.needsVersionChange, true); - expect(state.needsChangelogChange, true); + expect(state.needsVersionChange, false); + expect(state.needsChangelogChange, false); }); + test( + 'requires changelog or version change for doc comment changes', + () async { + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + ); + + const changedFiles = ['packages/a_plugin/lib/a_plugin.dart']; + + final GitVersionFinder git = FakeGitVersionFinder( + >{ + 'packages/a_plugin/lib/a_plugin.dart': [ + '- /// Old doc comment.', + '+ /// New doc comment.', + ], + }, + ); + + final PackageChangeState state = await checkPackageChangeState( + package, + changedPaths: changedFiles, + relativePackagePath: 'packages/a_plugin/', + git: git, + ); + + expect(state.hasChanges, true); + expect(state.needsVersionChange, true); + expect(state.needsChangelogChange, true); + }, + ); + test('requires changelog or version change for Dart code change', () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir); + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + ); - const List changedFiles = [ - 'packages/a_plugin/lib/a_plugin.dart', - ]; + const changedFiles = ['packages/a_plugin/lib/a_plugin.dart']; final GitVersionFinder git = FakeGitVersionFinder(>{ 'packages/a_plugin/lib/a_plugin.dart': [ @@ -443,56 +486,60 @@ void main() { // only comment changes. '- callOldMethod(); // inline comment', '+ callNewMethod(); // inline comment', - ] + ], }); - final PackageChangeState state = await checkPackageChangeState(package, - changedPaths: changedFiles, - relativePackagePath: 'packages/a_plugin/', - git: git); + final PackageChangeState state = await checkPackageChangeState( + package, + changedPaths: changedFiles, + relativePackagePath: 'packages/a_plugin/', + git: git, + ); expect(state.hasChanges, true); expect(state.needsVersionChange, true); expect(state.needsChangelogChange, true); }); - test( - 'requires changelog or version change if build.gradle diffs cannot ' + test('requires changelog or version change if build.gradle diffs cannot ' 'be checked', () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir); + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + ); - const List changedFiles = [ - 'packages/a_plugin/android/build.gradle', - ]; + const changedFiles = ['packages/a_plugin/android/build.gradle']; - final PackageChangeState state = await checkPackageChangeState(package, - changedPaths: changedFiles, - relativePackagePath: 'packages/a_plugin/'); + final PackageChangeState state = await checkPackageChangeState( + package, + changedPaths: changedFiles, + relativePackagePath: 'packages/a_plugin/', + ); expect(state.hasChanges, true); expect(state.needsVersionChange, true); expect(state.needsChangelogChange, true); }); - test( - 'requires changelog or version change if build.gradle diffs cannot ' + test('requires changelog or version change if build.gradle diffs cannot ' 'be determined', () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir); + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + ); - const List changedFiles = [ - 'packages/a_plugin/android/build.gradle', - ]; + const changedFiles = ['packages/a_plugin/android/build.gradle']; final GitVersionFinder git = FakeGitVersionFinder(>{ - 'packages/a_plugin/android/build.gradle': [] + 'packages/a_plugin/android/build.gradle': [], }); - final PackageChangeState state = await checkPackageChangeState(package, - changedPaths: changedFiles, - relativePackagePath: 'packages/a_plugin/', - git: git); + final PackageChangeState state = await checkPackageChangeState( + package, + changedPaths: changedFiles, + relativePackagePath: 'packages/a_plugin/', + git: git, + ); expect(state.hasChanges, true); expect(state.needsVersionChange, true); diff --git a/script/tool/test/common/plugin_utils_test.dart b/script/tool/test/common/plugin_utils_test.dart index 2c5a8f06899f..f468646f6e74 100644 --- a/script/tool/test/common/plugin_utils_test.dart +++ b/script/tool/test/common/plugin_utils_test.dart @@ -30,15 +30,18 @@ void main() { }); test('all platforms', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline), - platformIOS: const PlatformDetails(PlatformSupport.inline), - platformLinux: const PlatformDetails(PlatformSupport.inline), - platformMacOS: const PlatformDetails(PlatformSupport.inline), - platformWeb: const PlatformDetails(PlatformSupport.inline), - platformWindows: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + platformIOS: const PlatformDetails(PlatformSupport.inline), + platformLinux: const PlatformDetails(PlatformSupport.inline), + platformMacOS: const PlatformDetails(PlatformSupport.inline), + platformWeb: const PlatformDetails(PlatformSupport.inline), + platformWindows: const PlatformDetails(PlatformSupport.inline), + }, + ); expect(pluginSupportsPlatform(platformAndroid, plugin), isTrue); expect(pluginSupportsPlatform(platformIOS, plugin), isTrue); @@ -49,12 +52,15 @@ void main() { }); test('some platforms', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline), - platformLinux: const PlatformDetails(PlatformSupport.inline), - platformWeb: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + platformLinux: const PlatformDetails(PlatformSupport.inline), + platformWeb: const PlatformDetails(PlatformSupport.inline), + }, + ); expect(pluginSupportsPlatform(platformAndroid, plugin), isTrue); expect(pluginSupportsPlatform(platformIOS, plugin), isFalse); @@ -65,125 +71,227 @@ void main() { }); test('inline plugins are only detected as inline', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline), - platformIOS: const PlatformDetails(PlatformSupport.inline), - platformLinux: const PlatformDetails(PlatformSupport.inline), - platformMacOS: const PlatformDetails(PlatformSupport.inline), - platformWeb: const PlatformDetails(PlatformSupport.inline), - platformWindows: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + platformIOS: const PlatformDetails(PlatformSupport.inline), + platformLinux: const PlatformDetails(PlatformSupport.inline), + platformMacOS: const PlatformDetails(PlatformSupport.inline), + platformWeb: const PlatformDetails(PlatformSupport.inline), + platformWindows: const PlatformDetails(PlatformSupport.inline), + }, + ); expect( - pluginSupportsPlatform(platformAndroid, plugin, - requiredMode: PlatformSupport.inline), - isTrue); + pluginSupportsPlatform( + platformAndroid, + plugin, + requiredMode: PlatformSupport.inline, + ), + isTrue, + ); expect( - pluginSupportsPlatform(platformAndroid, plugin, - requiredMode: PlatformSupport.federated), - isFalse); + pluginSupportsPlatform( + platformAndroid, + plugin, + requiredMode: PlatformSupport.federated, + ), + isFalse, + ); expect( - pluginSupportsPlatform(platformIOS, plugin, - requiredMode: PlatformSupport.inline), - isTrue); + pluginSupportsPlatform( + platformIOS, + plugin, + requiredMode: PlatformSupport.inline, + ), + isTrue, + ); expect( - pluginSupportsPlatform(platformIOS, plugin, - requiredMode: PlatformSupport.federated), - isFalse); + pluginSupportsPlatform( + platformIOS, + plugin, + requiredMode: PlatformSupport.federated, + ), + isFalse, + ); expect( - pluginSupportsPlatform(platformLinux, plugin, - requiredMode: PlatformSupport.inline), - isTrue); + pluginSupportsPlatform( + platformLinux, + plugin, + requiredMode: PlatformSupport.inline, + ), + isTrue, + ); expect( - pluginSupportsPlatform(platformLinux, plugin, - requiredMode: PlatformSupport.federated), - isFalse); + pluginSupportsPlatform( + platformLinux, + plugin, + requiredMode: PlatformSupport.federated, + ), + isFalse, + ); expect( - pluginSupportsPlatform(platformMacOS, plugin, - requiredMode: PlatformSupport.inline), - isTrue); + pluginSupportsPlatform( + platformMacOS, + plugin, + requiredMode: PlatformSupport.inline, + ), + isTrue, + ); expect( - pluginSupportsPlatform(platformMacOS, plugin, - requiredMode: PlatformSupport.federated), - isFalse); + pluginSupportsPlatform( + platformMacOS, + plugin, + requiredMode: PlatformSupport.federated, + ), + isFalse, + ); expect( - pluginSupportsPlatform(platformWeb, plugin, - requiredMode: PlatformSupport.inline), - isTrue); + pluginSupportsPlatform( + platformWeb, + plugin, + requiredMode: PlatformSupport.inline, + ), + isTrue, + ); expect( - pluginSupportsPlatform(platformWeb, plugin, - requiredMode: PlatformSupport.federated), - isFalse); + pluginSupportsPlatform( + platformWeb, + plugin, + requiredMode: PlatformSupport.federated, + ), + isFalse, + ); expect( - pluginSupportsPlatform(platformWindows, plugin, - requiredMode: PlatformSupport.inline), - isTrue); + pluginSupportsPlatform( + platformWindows, + plugin, + requiredMode: PlatformSupport.inline, + ), + isTrue, + ); expect( - pluginSupportsPlatform(platformWindows, plugin, - requiredMode: PlatformSupport.federated), - isFalse); + pluginSupportsPlatform( + platformWindows, + plugin, + requiredMode: PlatformSupport.federated, + ), + isFalse, + ); }); test('federated plugins are only detected as federated', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.federated), - platformIOS: const PlatformDetails(PlatformSupport.federated), - platformLinux: const PlatformDetails(PlatformSupport.federated), - platformMacOS: const PlatformDetails(PlatformSupport.federated), - platformWeb: const PlatformDetails(PlatformSupport.federated), - platformWindows: const PlatformDetails(PlatformSupport.federated), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.federated), + platformIOS: const PlatformDetails(PlatformSupport.federated), + platformLinux: const PlatformDetails(PlatformSupport.federated), + platformMacOS: const PlatformDetails(PlatformSupport.federated), + platformWeb: const PlatformDetails(PlatformSupport.federated), + platformWindows: const PlatformDetails(PlatformSupport.federated), + }, + ); expect( - pluginSupportsPlatform(platformAndroid, plugin, - requiredMode: PlatformSupport.federated), - isTrue); + pluginSupportsPlatform( + platformAndroid, + plugin, + requiredMode: PlatformSupport.federated, + ), + isTrue, + ); expect( - pluginSupportsPlatform(platformAndroid, plugin, - requiredMode: PlatformSupport.inline), - isFalse); + pluginSupportsPlatform( + platformAndroid, + plugin, + requiredMode: PlatformSupport.inline, + ), + isFalse, + ); expect( - pluginSupportsPlatform(platformIOS, plugin, - requiredMode: PlatformSupport.federated), - isTrue); + pluginSupportsPlatform( + platformIOS, + plugin, + requiredMode: PlatformSupport.federated, + ), + isTrue, + ); expect( - pluginSupportsPlatform(platformIOS, plugin, - requiredMode: PlatformSupport.inline), - isFalse); + pluginSupportsPlatform( + platformIOS, + plugin, + requiredMode: PlatformSupport.inline, + ), + isFalse, + ); expect( - pluginSupportsPlatform(platformLinux, plugin, - requiredMode: PlatformSupport.federated), - isTrue); + pluginSupportsPlatform( + platformLinux, + plugin, + requiredMode: PlatformSupport.federated, + ), + isTrue, + ); expect( - pluginSupportsPlatform(platformLinux, plugin, - requiredMode: PlatformSupport.inline), - isFalse); + pluginSupportsPlatform( + platformLinux, + plugin, + requiredMode: PlatformSupport.inline, + ), + isFalse, + ); expect( - pluginSupportsPlatform(platformMacOS, plugin, - requiredMode: PlatformSupport.federated), - isTrue); + pluginSupportsPlatform( + platformMacOS, + plugin, + requiredMode: PlatformSupport.federated, + ), + isTrue, + ); expect( - pluginSupportsPlatform(platformMacOS, plugin, - requiredMode: PlatformSupport.inline), - isFalse); + pluginSupportsPlatform( + platformMacOS, + plugin, + requiredMode: PlatformSupport.inline, + ), + isFalse, + ); expect( - pluginSupportsPlatform(platformWeb, plugin, - requiredMode: PlatformSupport.federated), - isTrue); + pluginSupportsPlatform( + platformWeb, + plugin, + requiredMode: PlatformSupport.federated, + ), + isTrue, + ); expect( - pluginSupportsPlatform(platformWeb, plugin, - requiredMode: PlatformSupport.inline), - isFalse); + pluginSupportsPlatform( + platformWeb, + plugin, + requiredMode: PlatformSupport.inline, + ), + isFalse, + ); expect( - pluginSupportsPlatform(platformWindows, plugin, - requiredMode: PlatformSupport.federated), - isTrue); + pluginSupportsPlatform( + platformWindows, + plugin, + requiredMode: PlatformSupport.federated, + ), + isTrue, + ); expect( - pluginSupportsPlatform(platformWindows, plugin, - requiredMode: PlatformSupport.inline), - isFalse); + pluginSupportsPlatform( + platformWindows, + plugin, + requiredMode: PlatformSupport.inline, + ), + isFalse, + ); }); }); @@ -221,12 +329,18 @@ void main() { 'plugin', packagesDir, platformSupport: { - platformLinux: - const PlatformDetails(PlatformSupport.inline, hasDartCode: true), - platformMacOS: - const PlatformDetails(PlatformSupport.inline, hasDartCode: true), - platformWindows: - const PlatformDetails(PlatformSupport.inline, hasDartCode: true), + platformLinux: const PlatformDetails( + PlatformSupport.inline, + hasDartCode: true, + ), + platformMacOS: const PlatformDetails( + PlatformSupport.inline, + hasDartCode: true, + ), + platformWindows: const PlatformDetails( + PlatformSupport.inline, + hasDartCode: true, + ), }, ); @@ -240,12 +354,21 @@ void main() { 'plugin', packagesDir, platformSupport: { - platformLinux: const PlatformDetails(PlatformSupport.inline, - hasNativeCode: false, hasDartCode: true), - platformMacOS: const PlatformDetails(PlatformSupport.inline, - hasNativeCode: false, hasDartCode: true), - platformWindows: const PlatformDetails(PlatformSupport.inline, - hasNativeCode: false, hasDartCode: true), + platformLinux: const PlatformDetails( + PlatformSupport.inline, + hasNativeCode: false, + hasDartCode: true, + ), + platformMacOS: const PlatformDetails( + PlatformSupport.inline, + hasNativeCode: false, + hasDartCode: true, + ), + platformWindows: const PlatformDetails( + PlatformSupport.inline, + hasNativeCode: false, + hasDartCode: true, + ), }, ); diff --git a/script/tool/test/common/pub_utils_test.dart b/script/tool/test/common/pub_utils_test.dart index 7b3c55ecd110..d18b1290a239 100644 --- a/script/tool/test/common/pub_utils_test.dart +++ b/script/tool/test/common/pub_utils_test.dart @@ -19,66 +19,81 @@ void main() { }); test('runs with Dart for a non-Flutter package by default', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); - final MockPlatform platform = MockPlatform(); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); + final platform = MockPlatform(); await runPubGet(package, processRunner, platform); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall('dart', const ['pub', 'get'], package.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('dart', const ['pub', 'get'], package.path), + ]), + ); }); test('runs with Flutter for a Flutter package by default', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, isFlutter: true); - final MockPlatform platform = MockPlatform(); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + isFlutter: true, + ); + final platform = MockPlatform(); await runPubGet(package, processRunner, platform); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall('flutter', const ['pub', 'get'], package.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const ['pub', 'get'], package.path), + ]), + ); }); test('runs with Flutter for a Dart package when requested', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); - final MockPlatform platform = MockPlatform(); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); + final platform = MockPlatform(); await runPubGet(package, processRunner, platform, alwaysUseFlutter: true); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall('flutter', const ['pub', 'get'], package.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const ['pub', 'get'], package.path), + ]), + ); }); test('uses the correct Flutter command on Windows', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, isFlutter: true); - final MockPlatform platform = MockPlatform(isWindows: true); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + isFlutter: true, + ); + final platform = MockPlatform(isWindows: true); await runPubGet(package, processRunner, platform); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'flutter.bat', const ['pub', 'get'], package.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter.bat', const ['pub', 'get'], package.path), + ]), + ); }); test('reports success', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); - final MockPlatform platform = MockPlatform(); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); + final platform = MockPlatform(); final bool result = await runPubGet(package, processRunner, platform); @@ -86,12 +101,14 @@ void main() { }); test('reports failure', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); - final MockPlatform platform = MockPlatform(); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); + final platform = MockPlatform(); processRunner.mockProcessesForExecutable['dart'] = [ - FakeProcessInfo(MockProcess(exitCode: 1), ['pub', 'get']) + FakeProcessInfo(MockProcess(exitCode: 1), ['pub', 'get']), ]; final bool result = await runPubGet(package, processRunner, platform); diff --git a/script/tool/test/common/pub_version_finder_test.dart b/script/tool/test/common/pub_version_finder_test.dart index 9f1f5a932f9d..3bca80a7d8de 100644 --- a/script/tool/test/common/pub_version_finder_test.dart +++ b/script/tool/test/common/pub_version_finder_test.dart @@ -12,12 +12,13 @@ import 'package:test/test.dart'; void main() { test('Package does not exist.', () async { - final MockClient mockClient = MockClient((http.Request request) async { + final mockClient = MockClient((http.Request request) async { return http.Response('', 404); }); - final PubVersionFinder finder = PubVersionFinder(httpClient: mockClient); - final PubVersionFinderResponse response = - await finder.getPackageVersion(packageName: 'some_package'); + final finder = PubVersionFinder(httpClient: mockClient); + final PubVersionFinderResponse response = await finder.getPackageVersion( + packageName: 'some_package', + ); expect(response.versions, isEmpty); expect(response.result, PubVersionFinderResult.noPackageFound); @@ -26,12 +27,13 @@ void main() { }); test('HTTP error when getting versions from pub', () async { - final MockClient mockClient = MockClient((http.Request request) async { + final mockClient = MockClient((http.Request request) async { return http.Response('', 400); }); - final PubVersionFinder finder = PubVersionFinder(httpClient: mockClient); - final PubVersionFinderResponse response = - await finder.getPackageVersion(packageName: 'some_package'); + final finder = PubVersionFinder(httpClient: mockClient); + final PubVersionFinderResponse response = await finder.getPackageVersion( + packageName: 'some_package', + ); expect(response.versions, isEmpty); expect(response.result, PubVersionFinderResult.fail); @@ -40,7 +42,7 @@ void main() { }); test('Get a correct list of versions when http response is OK.', () async { - const Map httpResponse = { + const httpResponse = { 'name': 'some_package', 'versions': [ '0.0.1', @@ -57,12 +59,13 @@ void main() { '1.0.0', ], }; - final MockClient mockClient = MockClient((http.Request request) async { + final mockClient = MockClient((http.Request request) async { return http.Response(json.encode(httpResponse), 200); }); - final PubVersionFinder finder = PubVersionFinder(httpClient: mockClient); - final PubVersionFinderResponse response = - await finder.getPackageVersion(packageName: 'some_package'); + final finder = PubVersionFinder(httpClient: mockClient); + final PubVersionFinderResponse response = await finder.getPackageVersion( + packageName: 'some_package', + ); expect(response.versions, [ Version.parse('2.0.0'), diff --git a/script/tool/test/common/repository_package_test.dart b/script/tool/test/common/repository_package_test.dart index b43fb80fca51..be927d3f5b9f 100644 --- a/script/tool/test/common/repository_package_test.dart +++ b/script/tool/test/common/repository_package_test.dart @@ -24,59 +24,65 @@ void main() { 'foo', ); expect( - RepositoryPackage(packagesDir - .childDirectory('foo') - .childDirectory('bar') - .childDirectory('baz')) - .displayName, + RepositoryPackage( + packagesDir + .childDirectory('foo') + .childDirectory('bar') + .childDirectory('baz'), + ).displayName, 'foo/bar/baz', ); }); test('handles third_party/packages/', () async { expect( - RepositoryPackage(packagesDir.parent - .childDirectory('third_party') - .childDirectory('packages') - .childDirectory('foo') - .childDirectory('bar') - .childDirectory('baz')) - .displayName, + RepositoryPackage( + packagesDir.parent + .childDirectory('third_party') + .childDirectory('packages') + .childDirectory('foo') + .childDirectory('bar') + .childDirectory('baz'), + ).displayName, 'foo/bar/baz', ); }); test('always uses Posix-style paths', () async { final Directory windowsPackagesDir = createPackagesDirectory( - MemoryFileSystem(style: FileSystemStyle.windows)); + MemoryFileSystem(style: FileSystemStyle.windows), + ); expect( RepositoryPackage(windowsPackagesDir.childDirectory('foo')).displayName, 'foo', ); expect( - RepositoryPackage(windowsPackagesDir - .childDirectory('foo') - .childDirectory('bar') - .childDirectory('baz')) - .displayName, + RepositoryPackage( + windowsPackagesDir + .childDirectory('foo') + .childDirectory('bar') + .childDirectory('baz'), + ).displayName, 'foo/bar/baz', ); }); test('elides group name in grouped federated plugin structure', () async { expect( - RepositoryPackage(packagesDir - .childDirectory('a_plugin') - .childDirectory('a_plugin_platform_interface')) - .displayName, + RepositoryPackage( + packagesDir + .childDirectory('a_plugin') + .childDirectory('a_plugin_platform_interface'), + ).displayName, 'a_plugin_platform_interface', ); expect( - RepositoryPackage(packagesDir - .childDirectory('a_plugin') - .childDirectory('a_plugin_platform_web')) - .displayName, + RepositoryPackage( + packagesDir + .childDirectory('a_plugin') + .childDirectory('a_plugin_platform_web'), + ).displayName, 'a_plugin_platform_web', ); }); @@ -85,10 +91,9 @@ void main() { // with the group folder itself. test('does not elide group name for app-facing packages', () async { expect( - RepositoryPackage(packagesDir - .childDirectory('a_plugin') - .childDirectory('a_plugin')) - .displayName, + RepositoryPackage( + packagesDir.childDirectory('a_plugin').childDirectory('a_plugin'), + ).displayName, 'a_plugin/a_plugin', ); }); @@ -96,8 +101,10 @@ void main() { group('getExamples', () { test('handles a single Flutter example', () async { - final RepositoryPackage plugin = - createFakePlugin('a_plugin', packagesDir); + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + ); final List examples = plugin.getExamples().toList(); @@ -107,23 +114,32 @@ void main() { }); test('handles multiple Flutter examples', () async { - final RepositoryPackage plugin = createFakePlugin('a_plugin', packagesDir, - examples: ['example1', 'example2']); + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + examples: ['example1', 'example2'], + ); final List examples = plugin.getExamples().toList(); expect(examples.length, 2); expect(examples[0].isExample, isTrue); expect(examples[1].isExample, isTrue); - expect(examples[0].path, - getExampleDir(plugin).childDirectory('example1').path); - expect(examples[1].path, - getExampleDir(plugin).childDirectory('example2').path); + expect( + examples[0].path, + getExampleDir(plugin).childDirectory('example1').path, + ); + expect( + examples[1].path, + getExampleDir(plugin).childDirectory('example2').path, + ); }); test('handles a single non-Flutter example', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); final List examples = package.getExamples().toList(); @@ -134,25 +150,33 @@ void main() { test('handles multiple non-Flutter examples', () async { final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - examples: ['example1', 'example2']); + 'a_package', + packagesDir, + examples: ['example1', 'example2'], + ); final List examples = package.getExamples().toList(); expect(examples.length, 2); expect(examples[0].isExample, isTrue); expect(examples[1].isExample, isTrue); - expect(examples[0].path, - getExampleDir(package).childDirectory('example1').path); - expect(examples[1].path, - getExampleDir(package).childDirectory('example2').path); + expect( + examples[0].path, + getExampleDir(package).childDirectory('example1').path, + ); + expect( + examples[1].path, + getExampleDir(package).childDirectory('example2').path, + ); }); }); group('federated plugin queries', () { test('all return false for a simple plugin', () { - final RepositoryPackage plugin = - createFakePlugin('a_plugin', packagesDir); + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + ); expect(plugin.isFederated, false); expect(plugin.isAppFacing, false); expect(plugin.isPlatformInterface, false); @@ -161,8 +185,10 @@ void main() { }); test('handle app-facing packages', () { - final RepositoryPackage plugin = - createFakePlugin('a_plugin', packagesDir.childDirectory('a_plugin')); + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir.childDirectory('a_plugin'), + ); expect(plugin.isFederated, true); expect(plugin.isAppFacing, true); expect(plugin.isPlatformInterface, false); @@ -172,8 +198,9 @@ void main() { test('handle platform interface packages', () { final RepositoryPackage plugin = createFakePlugin( - 'a_plugin_platform_interface', - packagesDir.childDirectory('a_plugin')); + 'a_plugin_platform_interface', + packagesDir.childDirectory('a_plugin'), + ); expect(plugin.isFederated, true); expect(plugin.isAppFacing, false); expect(plugin.isPlatformInterface, true); @@ -185,7 +212,9 @@ void main() { // A platform interface can end with anything, not just one of the known // platform names, because of cases like webview_flutter_wkwebview. final RepositoryPackage plugin = createFakePlugin( - 'a_plugin_foo', packagesDir.childDirectory('a_plugin')); + 'a_plugin_foo', + packagesDir.childDirectory('a_plugin'), + ); expect(plugin.isFederated, true); expect(plugin.isAppFacing, false); expect(plugin.isPlatformInterface, false); @@ -196,8 +225,10 @@ void main() { group('pubspec', () { test('file', () async { - final RepositoryPackage plugin = - createFakePlugin('a_plugin', packagesDir); + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + ); final File pubspecFile = plugin.pubspecFile; @@ -205,8 +236,11 @@ void main() { }); test('parsing', () async { - final RepositoryPackage plugin = createFakePlugin('a_plugin', packagesDir, - examples: ['example1', 'example2']); + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + examples: ['example1', 'example2'], + ); final Pubspec pubspec = plugin.parsePubspec(); @@ -216,14 +250,19 @@ void main() { group('requiresFlutter', () { test('returns true for Flutter package', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, isFlutter: true); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + isFlutter: true, + ); expect(package.requiresFlutter(), true); }); test('returns true for a dev dependency on Flutter', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); final File pubspecFile = package.pubspecFile; final Pubspec pubspec = package.parsePubspec(); pubspec.devDependencies['flutter'] = SdkDependency('flutter'); @@ -233,8 +272,10 @@ void main() { }); test('returns false for non-Flutter package', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); expect(package.requiresFlutter(), false); }); }); diff --git a/script/tool/test/common/xcode_test.dart b/script/tool/test/common/xcode_test.dart index 365bcb0b6753..b123b7616fa5 100644 --- a/script/tool/test/common/xcode_test.dart +++ b/script/tool/test/common/xcode_test.dart @@ -24,11 +24,11 @@ void main() { group('findBestAvailableIphoneSimulator', () { test('finds the newest device', () async { - const String expectedDeviceId = '1E76A0FD-38AC-4537-A989-EA639D7D012A'; + const expectedDeviceId = '1E76A0FD-38AC-4537-A989-EA639D7D012A'; // Note: This uses `dynamic` deliberately, and should not be updated to // Object, in order to ensure that the code correctly handles this return // type from JSON decoding. - final Map devices = { + final devices = { 'runtimes': >[ { 'bundlePath': @@ -39,7 +39,7 @@ void main() { 'identifier': 'com.apple.CoreSimulator.SimRuntime.iOS-13-0', 'version': '13.0', 'isAvailable': true, - 'name': 'iOS 13.0' + 'name': 'iOS 13.0', }, { 'bundlePath': @@ -50,7 +50,7 @@ void main() { 'identifier': 'com.apple.CoreSimulator.SimRuntime.iOS-13-4', 'version': '13.4', 'isAvailable': true, - 'name': 'iOS 13.4' + 'name': 'iOS 13.4', }, { 'bundlePath': @@ -61,8 +61,8 @@ void main() { 'identifier': 'com.apple.CoreSimulator.SimRuntime.watchOS-6-2', 'version': '6.2.1', 'isAvailable': true, - 'name': 'watchOS 6.2' - } + 'name': 'watchOS 6.2', + }, ], 'devices': { 'com.apple.CoreSimulator.SimRuntime.iOS-13-4': >[ @@ -76,7 +76,7 @@ void main() { 'deviceTypeIdentifier': 'com.apple.CoreSimulator.SimDeviceType.iPhone-8', 'state': 'Shutdown', - 'name': 'iPhone 8' + 'name': 'iPhone 8', }, { 'dataPath': @@ -88,15 +88,17 @@ void main() { 'deviceTypeIdentifier': 'com.apple.CoreSimulator.SimDeviceType.iPhone-8-Plus', 'state': 'Shutdown', - 'name': 'iPhone 8 Plus' - } - ] - } + 'name': 'iPhone 8 Plus', + }, + ], + }, }; processRunner.mockProcessesForExecutable['xcrun'] = [ - FakeProcessInfo(MockProcess(stdout: jsonEncode(devices)), - ['simctl', 'list']), + FakeProcessInfo(MockProcess(stdout: jsonEncode(devices)), [ + 'simctl', + 'list', + ]), ]; expect(await xcode.findBestAvailableIphoneSimulator(), expectedDeviceId); @@ -106,7 +108,7 @@ void main() { // Note: This uses `dynamic` deliberately, and should not be updated to // Object, in order to ensure that the code correctly handles this return // type from JSON decoding. - final Map devices = { + final devices = { 'runtimes': >[ { 'bundlePath': @@ -117,12 +119,11 @@ void main() { 'identifier': 'com.apple.CoreSimulator.SimRuntime.watchOS-6-2', 'version': '6.2.1', 'isAvailable': true, - 'name': 'watchOS 6.2' - } + 'name': 'watchOS 6.2', + }, ], 'devices': { - 'com.apple.CoreSimulator.SimRuntime.watchOS-6-2': - >[ + 'com.apple.CoreSimulator.SimRuntime.watchOS-6-2': >[ { 'dataPath': '/Users/xxx/Library/Developer/CoreSimulator/Devices/1E76A0FD-38AC-4537-A989-EA639D7D012A/data', @@ -133,15 +134,17 @@ void main() { 'deviceTypeIdentifier': 'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-38mm', 'state': 'Shutdown', - 'name': 'Apple Watch' - } - ] - } + 'name': 'Apple Watch', + }, + ], + }, }; processRunner.mockProcessesForExecutable['xcrun'] = [ - FakeProcessInfo(MockProcess(stdout: jsonEncode(devices)), - ['simctl', 'list']), + FakeProcessInfo(MockProcess(stdout: jsonEncode(devices)), [ + 'simctl', + 'list', + ]), ]; expect(await xcode.findBestAvailableIphoneSimulator(), null); @@ -170,55 +173,54 @@ void main() { expect(exitCode, 0); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'xcrun', - const [ - 'xcodebuild', - 'build', - '-workspace', - 'A.xcworkspace', - '-scheme', - 'AScheme', - ], - directory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('xcrun', const [ + 'xcodebuild', + 'build', + '-workspace', + 'A.xcworkspace', + '-scheme', + 'AScheme', + ], directory.path), + ]), + ); }); test('handles all arguments', () async { final Directory directory = const LocalFileSystem().currentDirectory; - final int exitCode = await xcode.runXcodeBuild(directory, 'ios', - actions: ['action1', 'action2'], - workspace: 'A.xcworkspace', - scheme: 'AScheme', - configuration: 'Debug', - hostPlatform: MockPlatform(), - extraFlags: ['-a', '-b', 'c=d']); + final int exitCode = await xcode.runXcodeBuild( + directory, + 'ios', + actions: ['action1', 'action2'], + workspace: 'A.xcworkspace', + scheme: 'AScheme', + configuration: 'Debug', + hostPlatform: MockPlatform(), + extraFlags: ['-a', '-b', 'c=d'], + ); expect(exitCode, 0); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'xcrun', - const [ - 'xcodebuild', - 'action1', - 'action2', - '-workspace', - 'A.xcworkspace', - '-scheme', - 'AScheme', - '-configuration', - 'Debug', - '-a', - '-b', - 'c=d', - ], - directory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('xcrun', const [ + 'xcodebuild', + 'action1', + 'action2', + '-workspace', + 'A.xcworkspace', + '-scheme', + 'AScheme', + '-configuration', + 'Debug', + '-a', + '-b', + 'c=d', + ], directory.path), + ]), + ); }); test('returns error codes', () async { @@ -237,20 +239,18 @@ void main() { expect(exitCode, 1); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'xcrun', - const [ - 'xcodebuild', - 'build', - '-workspace', - 'A.xcworkspace', - '-scheme', - 'AScheme', - ], - directory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('xcrun', const [ + 'xcodebuild', + 'build', + '-workspace', + 'A.xcworkspace', + '-scheme', + 'AScheme', + ], directory.path), + ]), + ); }); test('sets CODE_SIGN_ENTITLEMENTS for macos tests', () async { @@ -273,27 +273,25 @@ void main() { expect(exitCode, 0); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'xcrun', - const [ - 'xcodebuild', - 'test', - '-workspace', - 'A.xcworkspace', - '-scheme', - 'AScheme', - 'CODE_SIGN_ENTITLEMENTS=/.tmp_rand0/flutter_disable_sandbox_entitlement.rand0/DebugProfileWithDisabledSandboxing.entitlements' - ], - directory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('xcrun', const [ + 'xcodebuild', + 'test', + '-workspace', + 'A.xcworkspace', + '-scheme', + 'AScheme', + 'CODE_SIGN_ENTITLEMENTS=/.tmp_rand0/flutter_disable_sandbox_entitlement.rand0/DebugProfileWithDisabledSandboxing.entitlements', + ], directory.path), + ]), + ); }); }); group('projectHasTarget', () { test('returns true when present', () async { - const String stdout = ''' + const stdout = ''' { "project" : { "configurations" : [ @@ -315,27 +313,26 @@ void main() { FakeProcessInfo(MockProcess(stdout: stdout), ['xcodebuild']), ]; - final Directory project = - const LocalFileSystem().directory('/foo.xcodeproj'); + final Directory project = const LocalFileSystem().directory( + '/foo.xcodeproj', + ); expect(await xcode.projectHasTarget(project, 'RunnerTests'), true); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'xcrun', - [ - 'xcodebuild', - '-list', - '-json', - '-project', - project.path, - ], - null), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('xcrun', [ + 'xcodebuild', + '-list', + '-json', + '-project', + project.path, + ], null), + ]), + ); }); test('returns false when not present', () async { - const String stdout = ''' + const stdout = ''' { "project" : { "configurations" : [ @@ -356,23 +353,22 @@ void main() { FakeProcessInfo(MockProcess(stdout: stdout), ['xcodebuild']), ]; - final Directory project = - const LocalFileSystem().directory('/foo.xcodeproj'); + final Directory project = const LocalFileSystem().directory( + '/foo.xcodeproj', + ); expect(await xcode.projectHasTarget(project, 'RunnerTests'), false); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'xcrun', - [ - 'xcodebuild', - '-list', - '-json', - '-project', - project.path, - ], - null), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('xcrun', [ + 'xcodebuild', + '-list', + '-json', + '-project', + project.path, + ], null), + ]), + ); }); test('returns null for unexpected output', () async { @@ -380,23 +376,22 @@ void main() { FakeProcessInfo(MockProcess(stdout: '{}'), ['xcodebuild']), ]; - final Directory project = - const LocalFileSystem().directory('/foo.xcodeproj'); + final Directory project = const LocalFileSystem().directory( + '/foo.xcodeproj', + ); expect(await xcode.projectHasTarget(project, 'RunnerTests'), null); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'xcrun', - [ - 'xcodebuild', - '-list', - '-json', - '-project', - project.path, - ], - null), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('xcrun', [ + 'xcodebuild', + '-list', + '-json', + '-project', + project.path, + ], null), + ]), + ); }); test('returns null for invalid output', () async { @@ -404,48 +399,48 @@ void main() { FakeProcessInfo(MockProcess(stdout: ':)'), ['xcodebuild']), ]; - final Directory project = - const LocalFileSystem().directory('/foo.xcodeproj'); + final Directory project = const LocalFileSystem().directory( + '/foo.xcodeproj', + ); expect(await xcode.projectHasTarget(project, 'RunnerTests'), null); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'xcrun', - [ - 'xcodebuild', - '-list', - '-json', - '-project', - project.path, - ], - null), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('xcrun', [ + 'xcodebuild', + '-list', + '-json', + '-project', + project.path, + ], null), + ]), + ); }); test('returns null for failure', () async { processRunner.mockProcessesForExecutable['xcrun'] = [ - FakeProcessInfo( - MockProcess(exitCode: 1), ['xcodebuild', '-list']) + FakeProcessInfo(MockProcess(exitCode: 1), [ + 'xcodebuild', + '-list', + ]), ]; - final Directory project = - const LocalFileSystem().directory('/foo.xcodeproj'); + final Directory project = const LocalFileSystem().directory( + '/foo.xcodeproj', + ); expect(await xcode.projectHasTarget(project, 'RunnerTests'), null); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'xcrun', - [ - 'xcodebuild', - '-list', - '-json', - '-project', - project.path, - ], - null), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('xcrun', [ + 'xcodebuild', + '-list', + '-json', + '-project', + project.path, + ], null), + ]), + ); }); }); } diff --git a/script/tool/test/create_all_packages_app_command_test.dart b/script/tool/test/create_all_packages_app_command_test.dart index 4a5fa7cdd05c..4e3b4c638ce2 100644 --- a/script/tool/test/create_all_packages_app_command_test.dart +++ b/script/tool/test/create_all_packages_app_command_test.dart @@ -35,7 +35,9 @@ void main() { platform: mockPlatform, ); runner = CommandRunner( - 'create_all_test', 'Test for $CreateAllPackagesAppCommand'); + 'create_all_test', + 'Test for $CreateAllPackagesAppCommand', + ); runner.addCommand(command); }); @@ -47,11 +49,13 @@ void main() { String? appBuildGradleDependencies, bool androidOnly = false, }) { - final RepositoryPackage package = RepositoryPackage( - outputDirectory.childDirectory(allPackagesProjectName)); + final package = RepositoryPackage( + outputDirectory.childDirectory(allPackagesProjectName), + ); // Android - final String dependencies = appBuildGradleDependencies ?? + final String dependencies = + appBuildGradleDependencies ?? r''' dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" @@ -158,7 +162,9 @@ project 'Runner', { platform: mockPlatform, ); runner = CommandRunner( - 'create_all_test', 'Test for $CreateAllPackagesAppCommand'); + 'create_all_test', + 'Test for $CreateAllPackagesAppCommand', + ); runner.addCommand(command); }); @@ -169,16 +175,16 @@ project 'Runner', { await runCapturingPrint(runner, ['create-all-packages-app']); expect( - processRunner.recordedCalls, - contains(ProcessCall( - getFlutterCommand(mockPlatform), - [ - 'create', - '--template=app', - '--project-name=$allPackagesProjectName', - testRoot.childDirectory(allPackagesProjectName).path, - ], - null))); + processRunner.recordedCalls, + contains( + ProcessCall(getFlutterCommand(mockPlatform), [ + 'create', + '--template=app', + '--project-name=$allPackagesProjectName', + testRoot.childDirectory(allPackagesProjectName).path, + ], null), + ), + ); }); test('pubspec includes all plugins', () async { @@ -191,12 +197,13 @@ project 'Runner', { final List pubspec = command.app.pubspecFile.readAsLinesSync(); expect( - pubspec, - containsAll([ - contains(RegExp('path: .*/packages/plugina')), - contains(RegExp('path: .*/packages/pluginb')), - contains(RegExp('path: .*/packages/pluginc')), - ])); + pubspec, + containsAll([ + contains(RegExp('path: .*/packages/plugina')), + contains(RegExp('path: .*/packages/pluginb')), + contains(RegExp('path: .*/packages/pluginc')), + ]), + ); }); test('pubspec has overrides for all plugins', () async { @@ -209,46 +216,54 @@ project 'Runner', { final List pubspec = command.app.pubspecFile.readAsLinesSync(); expect( - pubspec, - containsAllInOrder([ - contains('dependency_overrides:'), - contains(RegExp('path: .*/packages/plugina')), - contains(RegExp('path: .*/packages/pluginb')), - contains(RegExp('path: .*/packages/pluginc')), - ])); + pubspec, + containsAllInOrder([ + contains('dependency_overrides:'), + contains(RegExp('path: .*/packages/plugina')), + contains(RegExp('path: .*/packages/pluginb')), + contains(RegExp('path: .*/packages/pluginc')), + ]), + ); }); test( - 'pubspec special-cases camera_android_camerax to remove it from deps but not overrides', - () async { - writeFakeFlutterCreateOutput(testRoot); - final Directory cameraDir = packagesDir.childDirectory('camera'); - createFakePlugin('camera', cameraDir); - createFakePlugin('camera_android', cameraDir); - createFakePlugin('camera_android_camerax', cameraDir); - - await runCapturingPrint(runner, ['create-all-packages-app']); - final Pubspec pubspec = command.app.parsePubspec(); - - final Dependency? cameraDependency = pubspec.dependencies['camera']; - final Dependency? cameraAndroidDependency = - pubspec.dependencies['camera_android']; - final Dependency? cameraCameraXDependency = - pubspec.dependencies['camera_android_camerax']; - expect(cameraDependency, isA()); - expect((cameraDependency! as PathDependency).path, - endsWith('/packages/camera/camera')); - expect(cameraAndroidDependency, isA()); - expect((cameraAndroidDependency! as PathDependency).path, - endsWith('/packages/camera/camera_android')); - expect(cameraCameraXDependency, null); - - final Dependency? cameraCameraXOverride = - pubspec.dependencyOverrides['camera_android_camerax']; - expect(cameraCameraXOverride, isA()); - expect((cameraCameraXOverride! as PathDependency).path, - endsWith('/packages/camera/camera_android_camerax')); - }); + 'pubspec special-cases camera_android_camerax to remove it from deps but not overrides', + () async { + writeFakeFlutterCreateOutput(testRoot); + final Directory cameraDir = packagesDir.childDirectory('camera'); + createFakePlugin('camera', cameraDir); + createFakePlugin('camera_android', cameraDir); + createFakePlugin('camera_android_camerax', cameraDir); + + await runCapturingPrint(runner, ['create-all-packages-app']); + final Pubspec pubspec = command.app.parsePubspec(); + + final Dependency? cameraDependency = pubspec.dependencies['camera']; + final Dependency? cameraAndroidDependency = + pubspec.dependencies['camera_android']; + final Dependency? cameraCameraXDependency = + pubspec.dependencies['camera_android_camerax']; + expect(cameraDependency, isA()); + expect( + (cameraDependency! as PathDependency).path, + endsWith('/packages/camera/camera'), + ); + expect(cameraAndroidDependency, isA()); + expect( + (cameraAndroidDependency! as PathDependency).path, + endsWith('/packages/camera/camera_android'), + ); + expect(cameraCameraXDependency, null); + + final Dependency? cameraCameraXOverride = + pubspec.dependencyOverrides['camera_android_camerax']; + expect(cameraCameraXOverride, isA()); + expect( + (cameraCameraXOverride! as PathDependency).path, + endsWith('/packages/camera/camera_android_camerax'), + ); + }, + ); test('legacy files are copied when requested', () async { writeFakeFlutterCreateOutput(testRoot); @@ -256,10 +271,11 @@ project 'Runner', { // Make a fake legacy source with all the necessary files, replacing one // of them. final Directory legacyDir = testRoot.childDirectory('legacy'); - final RepositoryPackage legacySource = - RepositoryPackage(legacyDir.childDirectory(allPackagesProjectName)); + final legacySource = RepositoryPackage( + legacyDir.childDirectory(allPackagesProjectName), + ); writeFakeFlutterCreateOutput(legacyDir, androidOnly: true); - const String legacyAppBuildGradleContents = 'Fake legacy content'; + const legacyAppBuildGradleContents = 'Fake legacy content'; final File legacyGradleFile = legacySource .platformDirectory(FlutterPlatform.android) .childFile('build.gradle'); @@ -280,16 +296,16 @@ project 'Runner', { test('legacy directory replaces, rather than overlaying', () async { writeFakeFlutterCreateOutput(testRoot); createFakePlugin('plugina', packagesDir); - final File extraFile = - RepositoryPackage(testRoot.childDirectory(allPackagesProjectName)) - .platformDirectory(FlutterPlatform.android) - .childFile('extra_file'); + final File extraFile = RepositoryPackage( + testRoot.childDirectory(allPackagesProjectName), + ).platformDirectory(FlutterPlatform.android).childFile('extra_file'); extraFile.createSync(recursive: true); // Make a fake legacy source with all the necessary files, but not // including the extra file. final Directory legacyDir = testRoot.childDirectory('legacy'); - final RepositoryPackage legacySource = - RepositoryPackage(legacyDir.childDirectory(allPackagesProjectName)); + final legacySource = RepositoryPackage( + legacyDir.childDirectory(allPackagesProjectName), + ); writeFakeFlutterCreateOutput(legacyDir, androidOnly: true); await runCapturingPrint(runner, [ @@ -306,10 +322,11 @@ project 'Runner', { // Make a fake legacy source with all the necessary files, replacing one // of them. final Directory legacyDir = testRoot.childDirectory('legacy'); - final RepositoryPackage legacySource = - RepositoryPackage(legacyDir.childDirectory(allPackagesProjectName)); + final legacySource = RepositoryPackage( + legacyDir.childDirectory(allPackagesProjectName), + ); writeFakeFlutterCreateOutput(legacyDir, androidOnly: true); - const String legacyAppBuildGradleContents = ''' + const legacyAppBuildGradleContents = ''' # This is the legacy file android { compileSdk flutter.compileSdkVersion @@ -336,25 +353,30 @@ android { .readAsLinesSync(); expect( - buildGradle, - containsAll([ - contains('This is the legacy file'), - contains('compileSdk 36'), - ])); + buildGradle, + containsAll([ + contains('This is the legacy file'), + contains('compileSdk 36'), + ]), + ); }); test('pubspec preserves existing Dart SDK version', () async { - const String existingSdkConstraint = '>=1.0.0 <99.0.0'; - writeFakeFlutterCreateOutput(testRoot, - dartSdkConstraint: existingSdkConstraint); + const existingSdkConstraint = '>=1.0.0 <99.0.0'; + writeFakeFlutterCreateOutput( + testRoot, + dartSdkConstraint: existingSdkConstraint, + ); createFakePlugin('plugina', packagesDir); await runCapturingPrint(runner, ['create-all-packages-app']); final Pubspec generatedPubspec = command.app.parsePubspec(); - const String dartSdkKey = 'sdk'; - expect(generatedPubspec.environment[dartSdkKey].toString(), - existingSdkConstraint); + const dartSdkKey = 'sdk'; + expect( + generatedPubspec.environment[dartSdkKey].toString(), + existingSdkConstraint, + ); }); test('Android app gradle is modified as expected', () async { @@ -370,11 +392,12 @@ android { .readAsLinesSync(); expect( - buildGradle, - containsAll([ - contains('compileSdk 36'), - contains('androidx.lifecycle:lifecycle-runtime'), - ])); + buildGradle, + containsAll([ + contains('compileSdk 36'), + contains('androidx.lifecycle:lifecycle-runtime'), + ]), + ); }); // The template's app/build.gradle does not always have a dependencies @@ -392,38 +415,44 @@ android { .readAsLinesSync(); expect( - buildGradle, - containsAllInOrder([ - equals('dependencies {'), - contains('androidx.lifecycle:lifecycle-runtime'), - equals('}'), - ])); + buildGradle, + containsAllInOrder([ + equals('dependencies {'), + contains('androidx.lifecycle:lifecycle-runtime'), + equals('}'), + ]), + ); }); // Some versions of the template's app/build.gradle has an empty // dependencies section; ensure that the dependency is added in that case. - test('Android lifecyle dependency is added with empty dependencies', - () async { - writeFakeFlutterCreateOutput(testRoot, - appBuildGradleDependencies: 'dependencies {}'); - createFakePlugin('plugina', packagesDir); - - await runCapturingPrint(runner, ['create-all-packages-app']); - - final List buildGradle = command.app - .platformDirectory(FlutterPlatform.android) - .childDirectory('app') - .childFile('build.gradle') - .readAsLinesSync(); - - expect( + test( + 'Android lifecyle dependency is added with empty dependencies', + () async { + writeFakeFlutterCreateOutput( + testRoot, + appBuildGradleDependencies: 'dependencies {}', + ); + createFakePlugin('plugina', packagesDir); + + await runCapturingPrint(runner, ['create-all-packages-app']); + + final List buildGradle = command.app + .platformDirectory(FlutterPlatform.android) + .childDirectory('app') + .childFile('build.gradle') + .readAsLinesSync(); + + expect( buildGradle, containsAllInOrder([ equals('dependencies {'), contains('androidx.lifecycle:lifecycle-runtime'), equals('}'), - ])); - }); + ]), + ); + }, + ); test('macOS deployment target is modified in pbxproj', () async { writeFakeFlutterCreateOutput(testRoot); @@ -437,10 +466,13 @@ android { .readAsLinesSync(); expect( - pbxproj, - everyElement((String line) => + pbxproj, + everyElement( + (String line) => !line.contains('MACOSX_DEPLOYMENT_TARGET') || - line.contains('10.15'))); + line.contains('10.15'), + ), + ); }); test('iOS deployment target is modified in pbxproj', () async { @@ -455,10 +487,13 @@ android { .readAsLinesSync(); expect( - pbxproj, - everyElement((String line) => + pbxproj, + everyElement( + (String line) => !line.contains('IPHONEOS_DEPLOYMENT_TARGET') || - line.contains('14.0'))); + line.contains('14.0'), + ), + ); }); test('calls flutter pub get', () async { @@ -468,76 +503,92 @@ android { await runCapturingPrint(runner, ['create-all-packages-app']); expect( - processRunner.recordedCalls, - contains(ProcessCall( - getFlutterCommand(mockPlatform), - const ['pub', 'get'], - testRoot.childDirectory(allPackagesProjectName).path))); + processRunner.recordedCalls, + contains( + ProcessCall( + getFlutterCommand(mockPlatform), + const ['pub', 'get'], + testRoot.childDirectory(allPackagesProjectName).path, + ), + ), + ); }); test('fails if flutter create fails', () async { writeFakeFlutterCreateOutput(testRoot); createFakePlugin('plugina', packagesDir); - processRunner - .mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = - [ - FakeProcessInfo(MockProcess(exitCode: 1), ['create']) + processRunner.mockProcessesForExecutable[getFlutterCommand( + mockPlatform, + )] = [ + FakeProcessInfo(MockProcess(exitCode: 1), ['create']), ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['create-all-packages-app'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['create-all-packages-app'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Failed to `flutter create`'), - ])); + output, + containsAllInOrder([contains('Failed to `flutter create`')]), + ); }); - test('fails if flutter pub get fails', () async { - writeFakeFlutterCreateOutput(testRoot); - createFakePlugin('plugina', packagesDir); - - processRunner - .mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = - [ - FakeProcessInfo(MockProcess(), ['create']), - FakeProcessInfo(MockProcess(exitCode: 1), ['pub', 'get']) - ]; - Error? commandError; - final List output = await runCapturingPrint( - runner, ['create-all-packages-app'], errorHandler: (Error e) { - commandError = e; - }); - - expect(commandError, isA()); - expect( + test( + 'fails if flutter pub get fails', + () async { + writeFakeFlutterCreateOutput(testRoot); + createFakePlugin('plugina', packagesDir); + + processRunner.mockProcessesForExecutable[getFlutterCommand( + mockPlatform, + )] = [ + FakeProcessInfo(MockProcess(), ['create']), + FakeProcessInfo(MockProcess(exitCode: 1), ['pub', 'get']), + ]; + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['create-all-packages-app'], + errorHandler: (Error e) { + commandError = e; + }, + ); + + expect(commandError, isA()); + expect( output, containsAllInOrder([ contains( - "Failed to generate native build files via 'flutter pub get'"), - ])); - }, - // See comment about Windows in create_all_packages_app_command.dart - skip: io.Platform.isWindows); + "Failed to generate native build files via 'flutter pub get'", + ), + ]), + ); + }, + // See comment about Windows in create_all_packages_app_command.dart + skip: io.Platform.isWindows, + ); test('handles --output-dir', () async { - final Directory customOutputDir = - testRoot.fileSystem.systemTempDirectory.createTempSync(); + final Directory customOutputDir = testRoot.fileSystem.systemTempDirectory + .createTempSync(); writeFakeFlutterCreateOutput(customOutputDir); createFakePlugin('plugina', packagesDir); await runCapturingPrint(runner, [ 'create-all-packages-app', - '--output-dir=${customOutputDir.path}' + '--output-dir=${customOutputDir.path}', ]); - expect(command.app.path, - customOutputDir.childDirectory(allPackagesProjectName).path); + expect( + command.app.path, + customOutputDir.childDirectory(allPackagesProjectName).path, + ); }); test('logs exclusions', () async { @@ -546,16 +597,19 @@ android { createFakePlugin('pluginb', packagesDir); createFakePlugin('pluginc', packagesDir); - final List output = await runCapturingPrint(runner, - ['create-all-packages-app', '--exclude=pluginb,pluginc']); + final List output = await runCapturingPrint(runner, [ + 'create-all-packages-app', + '--exclude=pluginb,pluginc', + ]); expect( - output, - containsAllInOrder([ - 'Exluding the following plugins from the combined build:', - ' pluginb', - ' pluginc', - ])); + output, + containsAllInOrder([ + 'Exluding the following plugins from the combined build:', + ' pluginb', + ' pluginc', + ]), + ); }); }); @@ -567,36 +621,43 @@ android { platform: MockPlatform(isMacOS: true), ); runner = CommandRunner( - 'create_all_test', 'Test for $CreateAllPackagesAppCommand'); + 'create_all_test', + 'Test for $CreateAllPackagesAppCommand', + ); runner.addCommand(command); }); - test('macOS deployment target is modified in Podfile', () async { - writeFakeFlutterCreateOutput(testRoot); - createFakePlugin('plugina', packagesDir); - - final File podfileFile = RepositoryPackage( - command.packagesDir.parent.childDirectory(allPackagesProjectName)) - .platformDirectory(FlutterPlatform.macos) - .childFile('Podfile'); - podfileFile.createSync(recursive: true); - podfileFile.writeAsStringSync(""" + test( + 'macOS deployment target is modified in Podfile', + () async { + writeFakeFlutterCreateOutput(testRoot); + createFakePlugin('plugina', packagesDir); + + final File podfileFile = RepositoryPackage( + command.packagesDir.parent.childDirectory(allPackagesProjectName), + ).platformDirectory(FlutterPlatform.macos).childFile('Podfile'); + podfileFile.createSync(recursive: true); + podfileFile.writeAsStringSync(""" platform :osx, '10.11' # some other line """); - await runCapturingPrint(runner, ['create-all-packages-app']); - final List podfile = command.app - .platformDirectory(FlutterPlatform.macos) - .childFile('Podfile') - .readAsLinesSync(); + await runCapturingPrint(runner, ['create-all-packages-app']); + final List podfile = command.app + .platformDirectory(FlutterPlatform.macos) + .childFile('Podfile') + .readAsLinesSync(); - expect( + expect( podfile, - everyElement((String line) => - !line.contains('platform :osx') || line.contains("'10.15'"))); - }, - // Podfile is only generated (and thus only edited) on macOS. - skip: !io.Platform.isMacOS); + everyElement( + (String line) => + !line.contains('platform :osx') || line.contains("'10.15'"), + ), + ); + }, + // Podfile is only generated (and thus only edited) on macOS. + skip: !io.Platform.isMacOS, + ); }); } diff --git a/script/tool/test/custom_test_command_test.dart b/script/tool/test/custom_test_command_test.dart index f370fb9f9ce0..6075e9cbf1fa 100644 --- a/script/tool/test/custom_test_command_test.dart +++ b/script/tool/test/custom_test_command_test.dart @@ -24,7 +24,7 @@ void main() { final GitDir gitDir; (:packagesDir, :processRunner, gitProcessRunner: _, :gitDir) = configureBaseCommandMocks(platform: mockPlatform); - final CustomTestCommand analyzeCommand = CustomTestCommand( + final analyzeCommand = CustomTestCommand( packagesDir, processRunner: processRunner, platform: mockPlatform, @@ -32,116 +32,141 @@ void main() { ); runner = CommandRunner( - 'custom_test_command', 'Test for custom_test_command'); + 'custom_test_command', + 'Test for custom_test_command', + ); runner.addCommand(analyzeCommand); }); test('runs both new and legacy when both are present', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, extraFiles: [ - 'tool/run_tests.dart', - 'run_tests.sh', - ]); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + extraFiles: ['tool/run_tests.dart', 'run_tests.sh'], + ); - final List output = - await runCapturingPrint(runner, ['custom-test']); + final List output = await runCapturingPrint(runner, [ + 'custom-test', + ]); expect( - processRunner.recordedCalls, - containsAll([ - ProcessCall(package.directory.childFile('run_tests.sh').path, - const [], package.path), - ProcessCall('dart', const ['run', 'tool/run_tests.dart'], - package.path), - ])); + processRunner.recordedCalls, + containsAll([ + ProcessCall( + package.directory.childFile('run_tests.sh').path, + const [], + package.path, + ), + ProcessCall('dart', const [ + 'run', + 'tool/run_tests.dart', + ], package.path), + ]), + ); expect( - output, - containsAllInOrder([ - contains('Ran for 1 package(s)'), - ])); + output, + containsAllInOrder([contains('Ran for 1 package(s)')]), + ); }); test('runs when only new is present', () async { final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - extraFiles: ['tool/run_tests.dart']); + 'a_package', + packagesDir, + extraFiles: ['tool/run_tests.dart'], + ); - final List output = - await runCapturingPrint(runner, ['custom-test']); + final List output = await runCapturingPrint(runner, [ + 'custom-test', + ]); expect( - processRunner.recordedCalls, - containsAll([ - ProcessCall('dart', const ['run', 'tool/run_tests.dart'], - package.path), - ])); + processRunner.recordedCalls, + containsAll([ + ProcessCall('dart', const [ + 'run', + 'tool/run_tests.dart', + ], package.path), + ]), + ); expect( - output, - containsAllInOrder([ - contains('Ran for 1 package(s)'), - ])); + output, + containsAllInOrder([contains('Ran for 1 package(s)')]), + ); }); test('runs pub get before running Dart test script', () async { final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - extraFiles: ['tool/run_tests.dart']); + 'a_package', + packagesDir, + extraFiles: ['tool/run_tests.dart'], + ); await runCapturingPrint(runner, ['custom-test']); expect( - processRunner.recordedCalls, - containsAll([ - ProcessCall('dart', const ['pub', 'get'], package.path), - ProcessCall('dart', const ['run', 'tool/run_tests.dart'], - package.path), - ])); + processRunner.recordedCalls, + containsAll([ + ProcessCall('dart', const ['pub', 'get'], package.path), + ProcessCall('dart', const [ + 'run', + 'tool/run_tests.dart', + ], package.path), + ]), + ); }); test('runs when only legacy is present', () async { final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - extraFiles: ['run_tests.sh']); + 'a_package', + packagesDir, + extraFiles: ['run_tests.sh'], + ); - final List output = - await runCapturingPrint(runner, ['custom-test']); + final List output = await runCapturingPrint(runner, [ + 'custom-test', + ]); expect( - processRunner.recordedCalls, - containsAll([ - ProcessCall(package.directory.childFile('run_tests.sh').path, - const [], package.path), - ])); + processRunner.recordedCalls, + containsAll([ + ProcessCall( + package.directory.childFile('run_tests.sh').path, + const [], + package.path, + ), + ]), + ); expect( - output, - containsAllInOrder([ - contains('Ran for 1 package(s)'), - ])); + output, + containsAllInOrder([contains('Ran for 1 package(s)')]), + ); }); test('skips when neither is present', () async { createFakePackage('a_package', packagesDir); - final List output = - await runCapturingPrint(runner, ['custom-test']); + final List output = await runCapturingPrint(runner, [ + 'custom-test', + ]); expect(processRunner.recordedCalls, isEmpty); expect( - output, - containsAllInOrder([ - contains('Skipped 1 package(s)'), - ])); + output, + containsAllInOrder([contains('Skipped 1 package(s)')]), + ); }); test('fails if new fails', () async { - createFakePackage('a_package', packagesDir, extraFiles: [ - 'tool/run_tests.dart', - 'run_tests.sh', - ]); + createFakePackage( + 'a_package', + packagesDir, + extraFiles: ['tool/run_tests.dart', 'run_tests.sh'], + ); processRunner.mockProcessesForExecutable['dart'] = [ FakeProcessInfo(MockProcess(), ['pub', 'get']), @@ -150,24 +175,29 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['custom-test'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['custom-test'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('The following packages had errors:'), - contains('a_package') - ])); + output, + containsAllInOrder([ + contains('The following packages had errors:'), + contains('a_package'), + ]), + ); }); test('fails if pub get fails', () async { - createFakePackage('a_package', packagesDir, extraFiles: [ - 'tool/run_tests.dart', - 'run_tests.sh', - ]); + createFakePackage( + 'a_package', + packagesDir, + extraFiles: ['tool/run_tests.dart', 'run_tests.sh'], + ); processRunner.mockProcessesForExecutable['dart'] = [ FakeProcessInfo(MockProcess(exitCode: 1), ['pub', 'get']), @@ -175,45 +205,56 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['custom-test'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['custom-test'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('The following packages had errors:'), - contains('a_package:\n' - ' Unable to get script dependencies') - ])); + output, + containsAllInOrder([ + contains('The following packages had errors:'), + contains( + 'a_package:\n' + ' Unable to get script dependencies', + ), + ]), + ); }); test('fails if legacy fails', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, extraFiles: [ - 'tool/run_tests.dart', - 'run_tests.sh', - ]); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + extraFiles: ['tool/run_tests.dart', 'run_tests.sh'], + ); - processRunner.mockProcessesForExecutable[ - package.directory.childFile('run_tests.sh').path] = [ + processRunner.mockProcessesForExecutable[package.directory + .childFile('run_tests.sh') + .path] = [ FakeProcessInfo(MockProcess(exitCode: 1)), ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['custom-test'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['custom-test'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('The following packages had errors:'), - contains('a_package') - ])); + output, + containsAllInOrder([ + contains('The following packages had errors:'), + contains('a_package'), + ]), + ); }); }); @@ -223,7 +264,7 @@ void main() { final GitDir gitDir; (:packagesDir, :processRunner, gitProcessRunner: _, :gitDir) = configureBaseCommandMocks(platform: mockPlatform); - final CustomTestCommand analyzeCommand = CustomTestCommand( + final analyzeCommand = CustomTestCommand( packagesDir, processRunner: processRunner, platform: mockPlatform, @@ -231,78 +272,94 @@ void main() { ); runner = CommandRunner( - 'custom_test_command', 'Test for custom_test_command'); + 'custom_test_command', + 'Test for custom_test_command', + ); runner.addCommand(analyzeCommand); }); test('runs new and skips old when both are present', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, extraFiles: [ - 'tool/run_tests.dart', - 'run_tests.sh', - ]); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + extraFiles: ['tool/run_tests.dart', 'run_tests.sh'], + ); - final List output = - await runCapturingPrint(runner, ['custom-test']); + final List output = await runCapturingPrint(runner, [ + 'custom-test', + ]); expect( - processRunner.recordedCalls, - containsAll([ - ProcessCall('dart', const ['run', 'tool/run_tests.dart'], - package.path), - ])); + processRunner.recordedCalls, + containsAll([ + ProcessCall('dart', const [ + 'run', + 'tool/run_tests.dart', + ], package.path), + ]), + ); expect( - output, - containsAllInOrder([ - contains('Ran for 1 package(s)'), - ])); + output, + containsAllInOrder([contains('Ran for 1 package(s)')]), + ); }); test('runs when only new is present', () async { final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - extraFiles: ['tool/run_tests.dart']); + 'a_package', + packagesDir, + extraFiles: ['tool/run_tests.dart'], + ); - final List output = - await runCapturingPrint(runner, ['custom-test']); + final List output = await runCapturingPrint(runner, [ + 'custom-test', + ]); expect( - processRunner.recordedCalls, - containsAll([ - ProcessCall('dart', const ['run', 'tool/run_tests.dart'], - package.path), - ])); + processRunner.recordedCalls, + containsAll([ + ProcessCall('dart', const [ + 'run', + 'tool/run_tests.dart', + ], package.path), + ]), + ); expect( - output, - containsAllInOrder([ - contains('Ran for 1 package(s)'), - ])); + output, + containsAllInOrder([contains('Ran for 1 package(s)')]), + ); }); test('skips package when only legacy is present', () async { - createFakePackage('a_package', packagesDir, - extraFiles: ['run_tests.sh']); + createFakePackage( + 'a_package', + packagesDir, + extraFiles: ['run_tests.sh'], + ); - final List output = - await runCapturingPrint(runner, ['custom-test']); + final List output = await runCapturingPrint(runner, [ + 'custom-test', + ]); expect(processRunner.recordedCalls, isEmpty); expect( - output, - containsAllInOrder([ - contains('run_tests.sh is not supported on Windows'), - contains('Skipped 1 package(s)'), - ])); + output, + containsAllInOrder([ + contains('run_tests.sh is not supported on Windows'), + contains('Skipped 1 package(s)'), + ]), + ); }); test('fails if new fails', () async { - createFakePackage('a_package', packagesDir, extraFiles: [ - 'tool/run_tests.dart', - 'run_tests.sh', - ]); + createFakePackage( + 'a_package', + packagesDir, + extraFiles: ['tool/run_tests.dart', 'run_tests.sh'], + ); processRunner.mockProcessesForExecutable['dart'] = [ FakeProcessInfo(MockProcess(), ['pub', 'get']), @@ -311,17 +368,21 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['custom-test'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['custom-test'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('The following packages had errors:'), - contains('a_package') - ])); + output, + containsAllInOrder([ + contains('The following packages had errors:'), + contains('a_package'), + ]), + ); }); }); } diff --git a/script/tool/test/dart_test_command_test.dart b/script/tool/test/dart_test_command_test.dart index 6d17632409d6..1a16a3703b3f 100644 --- a/script/tool/test/dart_test_command_test.dart +++ b/script/tool/test/dart_test_command_test.dart @@ -27,7 +27,7 @@ void main() { final GitDir gitDir; (:packagesDir, :processRunner, :gitProcessRunner, :gitDir) = configureBaseCommandMocks(platform: mockPlatform); - final DartTestCommand command = DartTestCommand( + final command = DartTestCommand( packagesDir, processRunner: processRunner, platform: mockPlatform, @@ -39,135 +39,186 @@ void main() { }); test('legacy "test" name still works', () async { - final RepositoryPackage plugin = createFakePlugin('a_plugin', packagesDir, - extraFiles: ['test/a_test.dart']); + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + extraFiles: ['test/a_test.dart'], + ); await runCapturingPrint(runner, ['test']); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall(getFlutterCommand(mockPlatform), - const ['test', '--color'], plugin.path), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '--color', + ], plugin.path), ]), ); }); test('runs flutter test on each plugin', () async { - final RepositoryPackage plugin1 = createFakePlugin('plugin1', packagesDir, - extraFiles: ['test/empty_test.dart']); - final RepositoryPackage plugin2 = createFakePlugin('plugin2', packagesDir, - extraFiles: ['test/empty_test.dart']); + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + extraFiles: ['test/empty_test.dart'], + ); + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir, + extraFiles: ['test/empty_test.dart'], + ); await runCapturingPrint(runner, ['dart-test']); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall(getFlutterCommand(mockPlatform), - const ['test', '--color'], plugin1.path), - ProcessCall(getFlutterCommand(mockPlatform), - const ['test', '--color'], plugin2.path), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '--color', + ], plugin1.path), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '--color', + ], plugin2.path), ]), ); }); test('runs flutter test on Flutter package example tests', () async { - final RepositoryPackage plugin = createFakePlugin('a_plugin', packagesDir, - extraFiles: [ - 'test/empty_test.dart', - 'example/test/an_example_test.dart' - ]); + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + extraFiles: [ + 'test/empty_test.dart', + 'example/test/an_example_test.dart', + ], + ); await runCapturingPrint(runner, ['dart-test']); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall(getFlutterCommand(mockPlatform), - const ['test', '--color'], plugin.path), - ProcessCall(getFlutterCommand(mockPlatform), - const ['test', '--color'], getExampleDir(plugin).path), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '--color', + ], plugin.path), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '--color', + ], getExampleDir(plugin).path), ]), ); }); test('fails when Flutter tests fail', () async { - createFakePlugin('plugin1', packagesDir, - extraFiles: ['test/empty_test.dart']); - createFakePlugin('plugin2', packagesDir, - extraFiles: ['test/empty_test.dart']); - - processRunner - .mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = - [ - FakeProcessInfo( - MockProcess(exitCode: 1), ['dart-test']), // plugin 1 test + createFakePlugin( + 'plugin1', + packagesDir, + extraFiles: ['test/empty_test.dart'], + ); + createFakePlugin( + 'plugin2', + packagesDir, + extraFiles: ['test/empty_test.dart'], + ); + + processRunner.mockProcessesForExecutable[getFlutterCommand( + mockPlatform, + )] = [ + FakeProcessInfo(MockProcess(exitCode: 1), [ + 'dart-test', + ]), // plugin 1 test FakeProcessInfo(MockProcess(), ['dart-test']), // plugin 2 test ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['dart-test'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['dart-test'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('The following packages had errors:'), - contains(' plugin1'), - ])); + output, + containsAllInOrder([ + contains('The following packages had errors:'), + contains(' plugin1'), + ]), + ); }); test('skips testing plugins without test directory', () async { createFakePlugin('plugin1', packagesDir); - final RepositoryPackage plugin2 = createFakePlugin('plugin2', packagesDir, - extraFiles: ['test/empty_test.dart']); + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir, + extraFiles: ['test/empty_test.dart'], + ); await runCapturingPrint(runner, ['dart-test']); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall(getFlutterCommand(mockPlatform), - const ['test', '--color'], plugin2.path), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '--color', + ], plugin2.path), ]), ); }); test('runs dart run test on non-Flutter packages', () async { - final RepositoryPackage plugin = createFakePlugin('a', packagesDir, - extraFiles: ['test/empty_test.dart']); - final RepositoryPackage package = createFakePackage('b', packagesDir, - extraFiles: ['test/empty_test.dart']); + final RepositoryPackage plugin = createFakePlugin( + 'a', + packagesDir, + extraFiles: ['test/empty_test.dart'], + ); + final RepositoryPackage package = createFakePackage( + 'b', + packagesDir, + extraFiles: ['test/empty_test.dart'], + ); - await runCapturingPrint( - runner, ['dart-test', '--enable-experiment=exp1']); + await runCapturingPrint(runner, [ + 'dart-test', + '--enable-experiment=exp1', + ]); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const ['test', '--color', '--enable-experiment=exp1'], - plugin.path), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '--color', + '--enable-experiment=exp1', + ], plugin.path), ProcessCall('dart', const ['pub', 'get'], package.path), - ProcessCall( - 'dart', - const ['run', '--enable-experiment=exp1', 'test'], - package.path), + ProcessCall('dart', const [ + 'run', + '--enable-experiment=exp1', + 'test', + ], package.path), ]), ); }); test('runs dart run test on non-Flutter package examples', () async { final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, extraFiles: [ - 'test/empty_test.dart', - 'example/test/an_example_test.dart' - ]); + 'a_package', + packagesDir, + extraFiles: [ + 'test/empty_test.dart', + 'example/test/an_example_test.dart', + ], + ); await runCapturingPrint(runner, ['dart-test']); @@ -176,41 +227,55 @@ void main() { orderedEquals([ ProcessCall('dart', const ['pub', 'get'], package.path), ProcessCall('dart', const ['run', 'test'], package.path), - ProcessCall('dart', const ['pub', 'get'], - getExampleDir(package).path), - ProcessCall('dart', const ['run', 'test'], - getExampleDir(package).path), + ProcessCall('dart', const [ + 'pub', + 'get', + ], getExampleDir(package).path), + ProcessCall('dart', const [ + 'run', + 'test', + ], getExampleDir(package).path), ]), ); }); test('fails when getting non-Flutter package dependencies fails', () async { - createFakePackage('a_package', packagesDir, - extraFiles: ['test/empty_test.dart']); + createFakePackage( + 'a_package', + packagesDir, + extraFiles: ['test/empty_test.dart'], + ); processRunner.mockProcessesForExecutable['dart'] = [ - FakeProcessInfo(MockProcess(exitCode: 1), ['pub', 'get']) + FakeProcessInfo(MockProcess(exitCode: 1), ['pub', 'get']), ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['dart-test'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['dart-test'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Unable to fetch dependencies'), - contains('The following packages had errors:'), - contains(' a_package'), - ])); + output, + containsAllInOrder([ + contains('Unable to fetch dependencies'), + contains('The following packages had errors:'), + contains(' a_package'), + ]), + ); }); test('fails when non-Flutter tests fail', () async { - createFakePackage('a_package', packagesDir, - extraFiles: ['test/empty_test.dart']); + createFakePackage( + 'a_package', + packagesDir, + extraFiles: ['test/empty_test.dart'], + ); processRunner.mockProcessesForExecutable['dart'] = [ FakeProcessInfo(MockProcess(), ['pub', 'get']), @@ -219,17 +284,21 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['dart-test'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['dart-test'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('The following packages had errors:'), - contains(' a_package'), - ])); + output, + containsAllInOrder([ + contains('The following packages had errors:'), + contains(' a_package'), + ]), + ); }); test('converts --platform=vm to no argument for flutter test', () async { @@ -244,8 +313,10 @@ void main() { expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall(getFlutterCommand(mockPlatform), - const ['test', '--color'], plugin.path), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '--color', + ], plugin.path), ]), ); }); @@ -262,23 +333,26 @@ test_on: unknown Error? commandError; final List output = await runCapturingPrint( - runner, ['dart-test', '--platform=vm'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['dart-test', '--platform=vm'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder( - [ - contains('Unknown "test_on" value: "unknown"\n' - "If this value needs to be supported for this package's " - 'tests, please update the repository tooling to support more ' - 'test_on modes.'), - ], - )); + output, + containsAllInOrder([ + contains( + 'Unknown "test_on" value: "unknown"\n' + "If this value needs to be supported for this package's " + 'tests, please update the repository tooling to support more ' + 'test_on modes.', + ), + ]), + ); }); test('throws for an valid but complex test_on directive', () async { @@ -293,23 +367,26 @@ test_on: vm && browser Error? commandError; final List output = await runCapturingPrint( - runner, ['dart-test', '--platform=vm'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['dart-test', '--platform=vm'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder( - [ - contains('Unknown "test_on" value: "vm && browser"\n' - "If this value needs to be supported for this package's " - 'tests, please update the repository tooling to support more ' - 'test_on modes.'), - ], - )); + output, + containsAllInOrder([ + contains( + 'Unknown "test_on" value: "vm && browser"\n' + "If this value needs to be supported for this package's " + 'tests, please update the repository tooling to support more ' + 'test_on modes.', + ), + ]), + ); }); test('runs in Chrome when requested for Flutter package', () async { @@ -320,20 +397,19 @@ test_on: vm && browser extraFiles: ['test/empty_test.dart'], ); - await runCapturingPrint( - runner, ['dart-test', '--platform=chrome']); + await runCapturingPrint(runner, [ + 'dart-test', + '--platform=chrome', + ]); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '--color', - '--platform=chrome', - ], - package.path), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '--color', + '--platform=chrome', + ], package.path), ]), ); }); @@ -346,110 +422,111 @@ test_on: vm && browser extraFiles: ['test/empty_test.dart'], ); - await runCapturingPrint( - runner, ['dart-test', '--platform=chrome', '--wasm']); - - expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '--color', - '--platform=chrome', - '--wasm', - ], - package.path), - ]), - ); - }); - - test('runs in Chrome by default for Flutter plugins that implement web', - () async { - final RepositoryPackage plugin = createFakePlugin( - 'some_plugin_web', - packagesDir, - extraFiles: ['test/empty_test.dart'], - platformSupport: { - platformWeb: const PlatformDetails(PlatformSupport.inline), - }, - ); - - await runCapturingPrint(runner, ['dart-test']); + await runCapturingPrint(runner, [ + 'dart-test', + '--platform=chrome', + '--wasm', + ]); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '--color', - '--platform=chrome', - ], - plugin.path), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '--color', + '--platform=chrome', + '--wasm', + ], package.path), ]), ); }); - test('runs in Chrome when requested for Flutter plugins that implement web', - () async { - final RepositoryPackage plugin = createFakePlugin( - 'some_plugin_web', - packagesDir, - extraFiles: ['test/empty_test.dart'], - platformSupport: { - platformWeb: const PlatformDetails(PlatformSupport.inline), - }, - ); - - await runCapturingPrint( - runner, ['dart-test', '--platform=chrome']); + test( + 'runs in Chrome by default for Flutter plugins that implement web', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'some_plugin_web', + packagesDir, + extraFiles: ['test/empty_test.dart'], + platformSupport: { + platformWeb: const PlatformDetails(PlatformSupport.inline), + }, + ); - expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '--color', - '--platform=chrome', - ], - plugin.path), - ]), - ); - }); + await runCapturingPrint(runner, ['dart-test']); - test('runs in Chrome when requested for Flutter plugin that endorse web', - () async { - final RepositoryPackage plugin = createFakePlugin( - 'plugin', - packagesDir, - extraFiles: ['test/empty_test.dart'], - platformSupport: { - platformWeb: const PlatformDetails(PlatformSupport.federated), - }, - ); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '--color', + '--platform=chrome', + ], plugin.path), + ]), + ); + }, + ); + + test( + 'runs in Chrome when requested for Flutter plugins that implement web', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'some_plugin_web', + packagesDir, + extraFiles: ['test/empty_test.dart'], + platformSupport: { + platformWeb: const PlatformDetails(PlatformSupport.inline), + }, + ); + + await runCapturingPrint(runner, [ + 'dart-test', + '--platform=chrome', + ]); - await runCapturingPrint( - runner, ['dart-test', '--platform=chrome']); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '--color', + '--platform=chrome', + ], plugin.path), + ]), + ); + }, + ); + + test( + 'runs in Chrome when requested for Flutter plugin that endorse web', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: ['test/empty_test.dart'], + platformSupport: { + platformWeb: const PlatformDetails(PlatformSupport.federated), + }, + ); + + await runCapturingPrint(runner, [ + 'dart-test', + '--platform=chrome', + ]); - expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '--color', - '--platform=chrome', - ], - plugin.path), - ]), - ); - }); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '--color', + '--platform=chrome', + ], plugin.path), + ]), + ); + }, + ); test('skips running non-web plugins in browser mode', () async { createFakePlugin( @@ -458,18 +535,18 @@ test_on: vm && browser extraFiles: ['test/empty_test.dart'], ); - final List output = await runCapturingPrint( - runner, ['dart-test', '--platform=chrome']); + final List output = await runCapturingPrint(runner, [ + 'dart-test', + '--platform=chrome', + ]); expect( - output, - containsAllInOrder([ - contains("Non-web plugin tests don't need web testing."), - ])); - expect( - processRunner.recordedCalls, - orderedEquals([]), + output, + containsAllInOrder([ + contains("Non-web plugin tests don't need web testing."), + ]), ); + expect(processRunner.recordedCalls, orderedEquals([])); }); test('skips running web plugins in explicit vm mode', () async { @@ -482,18 +559,18 @@ test_on: vm && browser }, ); - final List output = await runCapturingPrint( - runner, ['dart-test', '--platform=vm']); + final List output = await runCapturingPrint(runner, [ + 'dart-test', + '--platform=vm', + ]); expect( - output, - containsAllInOrder([ - contains("Web plugin tests don't need vm testing."), - ])); - expect( - processRunner.recordedCalls, - orderedEquals([]), + output, + containsAllInOrder([ + contains("Web plugin tests don't need vm testing."), + ]), ); + expect(processRunner.recordedCalls, orderedEquals([])); }); test('does not skip for plugins that endorse web', () async { @@ -507,20 +584,19 @@ test_on: vm && browser }, ); - await runCapturingPrint( - runner, ['dart-test', '--platform=chrome']); + await runCapturingPrint(runner, [ + 'dart-test', + '--platform=chrome', + ]); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '--color', - '--platform=chrome', - ], - plugin.path), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '--color', + '--platform=chrome', + ], plugin.path), ]), ); }); @@ -532,15 +608,20 @@ test_on: vm && browser extraFiles: ['test/empty_test.dart'], ); - await runCapturingPrint( - runner, ['dart-test', '--platform=chrome']); + await runCapturingPrint(runner, [ + 'dart-test', + '--platform=chrome', + ]); expect( processRunner.recordedCalls, orderedEquals([ ProcessCall('dart', const ['pub', 'get'], package.path), - ProcessCall('dart', - const ['run', 'test', '--platform=chrome'], package.path), + ProcessCall('dart', const [ + 'run', + 'test', + '--platform=chrome', + ], package.path), ]), ); }); @@ -552,22 +633,22 @@ test_on: vm && browser extraFiles: ['test/empty_test.dart'], ); - await runCapturingPrint( - runner, ['dart-test', '--platform=chrome', '--wasm']); + await runCapturingPrint(runner, [ + 'dart-test', + '--platform=chrome', + '--wasm', + ]); expect( processRunner.recordedCalls, orderedEquals([ ProcessCall('dart', const ['pub', 'get'], package.path), - ProcessCall( - 'dart', - const [ - 'run', - 'test', - '--platform=chrome', - '--compiler=dart2wasm', - ], - package.path), + ProcessCall('dart', const [ + 'run', + 'test', + '--platform=chrome', + '--compiler=dart2wasm', + ], package.path), ]), ); }); @@ -582,18 +663,18 @@ test_on: vm && browser test_on: vm '''); - final List output = await runCapturingPrint( - runner, ['dart-test', '--platform=chrome']); + final List output = await runCapturingPrint(runner, [ + 'dart-test', + '--platform=chrome', + ]); expect( - output, - containsAllInOrder([ - contains('Package has opted out of non-vm testing.'), - ])); - expect( - processRunner.recordedCalls, - orderedEquals([]), + output, + containsAllInOrder([ + contains('Package has opted out of non-vm testing.'), + ]), ); + expect(processRunner.recordedCalls, orderedEquals([])); }); test('does not skip running vm in vm mode', () async { @@ -606,18 +687,16 @@ test_on: vm test_on: vm '''); - final List output = await runCapturingPrint( - runner, ['dart-test', '--platform=vm']); + final List output = await runCapturingPrint(runner, [ + 'dart-test', + '--platform=vm', + ]); expect( - output, - isNot(containsAllInOrder([ - contains('Package has opted out'), - ]))); - expect( - processRunner.recordedCalls, - isNotEmpty, + output, + isNot(containsAllInOrder([contains('Package has opted out')])), ); + expect(processRunner.recordedCalls, isNotEmpty); }); test('skips running in vm mode if package opts out', () async { @@ -630,18 +709,18 @@ test_on: vm test_on: browser '''); - final List output = await runCapturingPrint( - runner, ['dart-test', '--platform=vm']); + final List output = await runCapturingPrint(runner, [ + 'dart-test', + '--platform=vm', + ]); expect( - output, - containsAllInOrder([ - contains('Package has opted out of vm testing.'), - ])); - expect( - processRunner.recordedCalls, - orderedEquals([]), + output, + containsAllInOrder([ + contains('Package has opted out of vm testing.'), + ]), ); + expect(processRunner.recordedCalls, orderedEquals([])); }); test('does not skip running browser in browser mode', () async { @@ -654,63 +733,73 @@ test_on: browser test_on: browser '''); - final List output = await runCapturingPrint( - runner, ['dart-test', '--platform=browser']); + final List output = await runCapturingPrint(runner, [ + 'dart-test', + '--platform=browser', + ]); expect( - output, - isNot(containsAllInOrder([ - contains('Package has opted out'), - ]))); - expect( - processRunner.recordedCalls, - isNotEmpty, + output, + isNot(containsAllInOrder([contains('Package has opted out')])), ); + expect(processRunner.recordedCalls, isNotEmpty); }); - test('tries to run for a test_on that the tool does not recognize', - () async { - final RepositoryPackage package = createFakePackage( - 'a_package', - packagesDir, - extraFiles: ['test/empty_test.dart'], - ); - package.directory.childFile('dart_test.yaml').writeAsStringSync(''' + test( + 'tries to run for a test_on that the tool does not recognize', + () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + extraFiles: ['test/empty_test.dart'], + ); + package.directory.childFile('dart_test.yaml').writeAsStringSync(''' test_on: !vm && firefox '''); - await runCapturingPrint(runner, ['dart-test']); + await runCapturingPrint(runner, ['dart-test']); - expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall('dart', const ['pub', 'get'], package.path), - ProcessCall('dart', const ['run', 'test'], package.path), - ]), - ); - }); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('dart', const ['pub', 'get'], package.path), + ProcessCall('dart', const ['run', 'test'], package.path), + ]), + ); + }, + ); test('enable-experiment flag', () async { - final RepositoryPackage plugin = createFakePlugin('a', packagesDir, - extraFiles: ['test/empty_test.dart']); - final RepositoryPackage package = createFakePackage('b', packagesDir, - extraFiles: ['test/empty_test.dart']); + final RepositoryPackage plugin = createFakePlugin( + 'a', + packagesDir, + extraFiles: ['test/empty_test.dart'], + ); + final RepositoryPackage package = createFakePackage( + 'b', + packagesDir, + extraFiles: ['test/empty_test.dart'], + ); - await runCapturingPrint( - runner, ['dart-test', '--enable-experiment=exp1']); + await runCapturingPrint(runner, [ + 'dart-test', + '--enable-experiment=exp1', + ]); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const ['test', '--color', '--enable-experiment=exp1'], - plugin.path), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '--color', + '--enable-experiment=exp1', + ], plugin.path), ProcessCall('dart', const ['pub', 'get'], package.path), - ProcessCall( - 'dart', - const ['run', '--enable-experiment=exp1', 'test'], - package.path), + ProcessCall('dart', const [ + 'run', + '--enable-experiment=exp1', + 'test', + ], package.path), ]), ); }); @@ -721,22 +810,26 @@ test_on: !vm && firefox gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' packages/package_a/foo.dart -''')), - ]; +''', + ), + ), + ]; - final List output = - await runCapturingPrint(runner, ['test']); + final List output = await runCapturingPrint(runner, [ + 'test', + ]); expect( - output, - containsAllInOrder([ - contains('Running for package_a'), - ])); + output, + containsAllInOrder([contains('Running for package_a')]), + ); }); - const List files = [ + const files = [ 'foo.java', 'foo.kt', 'foo.m', @@ -746,30 +839,36 @@ packages/package_a/foo.dart 'foo.cpp', 'foo.h', ]; - for (final String file in files) { + for (final file in files) { test('skips command for changes to non-Dart source $file', () async { createFakePackage('package_a', packagesDir); gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: + ''' packages/package_a/$file -''')), - ]; +''', + ), + ), + ]; - final List output = - await runCapturingPrint(runner, ['test']); + final List output = await runCapturingPrint(runner, [ + 'test', + ]); expect( - output, - isNot(containsAllInOrder([ - contains('Running for package_a'), - ]))); + output, + isNot( + containsAllInOrder([contains('Running for package_a')]), + ), + ); expect( - output, - containsAllInOrder([ - contains('SKIPPING ALL PACKAGES'), - ])); + output, + containsAllInOrder([contains('SKIPPING ALL PACKAGES')]), + ); }); } @@ -778,26 +877,31 @@ packages/package_a/$file gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' README.md CODEOWNERS packages/package_a/CHANGELOG.md -''')), - ]; +''', + ), + ), + ]; - final List output = - await runCapturingPrint(runner, ['test']); + final List output = await runCapturingPrint(runner, [ + 'test', + ]); expect( - output, - isNot(containsAllInOrder([ - contains('Running for package_a'), - ]))); + output, + isNot( + containsAllInOrder([contains('Running for package_a')]), + ), + ); expect( - output, - containsAllInOrder([ - contains('SKIPPING ALL PACKAGES'), - ])); + output, + containsAllInOrder([contains('SKIPPING ALL PACKAGES')]), + ); }); }); }); diff --git a/script/tool/test/dependabot_check_command_test.dart b/script/tool/test/dependabot_check_command_test.dart index 6c9bf4ea3194..630c6f535805 100644 --- a/script/tool/test/dependabot_check_command_test.dart +++ b/script/tool/test/dependabot_check_command_test.dart @@ -22,12 +22,11 @@ void main() { configureBaseCommandMocks(); root = packagesDir.parent; - final DependabotCheckCommand command = DependabotCheckCommand( - packagesDir, - gitDir: gitDir, - ); + final command = DependabotCheckCommand(packagesDir, gitDir: gitDir); runner = CommandRunner( - 'dependabot_test', 'Test for $DependabotCheckCommand'); + 'dependabot_test', + 'Test for $DependabotCheckCommand', + ); runner.addCommand(command); }); @@ -37,7 +36,8 @@ void main() { }) { final String gradleEntries; if (useDirectoriesKey) { - gradleEntries = ''' + gradleEntries = + ''' - package-ecosystem: "gradle" directories: ${gradleDirs.map((String directory) => ' - /$directory').join('\n')} @@ -45,15 +45,21 @@ ${gradleDirs.map((String directory) => ' - /$directory').join('\n')} interval: "daily" '''; } else { - gradleEntries = gradleDirs.map((String directory) => ''' + gradleEntries = gradleDirs + .map( + (String directory) => + ''' - package-ecosystem: "gradle" directory: "/$directory" schedule: interval: "daily" -''').join('\n'); +''', + ) + .join('\n'); } - final File configFile = - root.childDirectory('.github').childFile('dependabot.yml'); + final File configFile = root + .childDirectory('.github') + .childFile('dependabot.yml'); configFile.createSync(recursive: true); configFile.writeAsStringSync(''' version: 2 @@ -66,20 +72,24 @@ $gradleEntries setDependabotCoverage(); createFakePackage('a_package', packagesDir); - final List output = - await runCapturingPrint(runner, ['dependabot-check']); + final List output = await runCapturingPrint(runner, [ + 'dependabot-check', + ]); expect( - output, - containsAllInOrder([ - contains('SKIPPING: No supported package ecosystems'), - ])); + output, + containsAllInOrder([ + contains('SKIPPING: No supported package ecosystems'), + ]), + ); }); test('fails for app missing Gradle coverage', () async { setDependabotCoverage(); - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); package.directory .childDirectory('example') .childDirectory('android') @@ -88,20 +98,27 @@ $gradleEntries Error? commandError; final List output = await runCapturingPrint( - runner, ['dependabot-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['dependabot-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Missing Gradle coverage.'), - contains( - 'Add a "gradle" entry to .github/dependabot.yml for /packages/a_package/example/android/app'), - contains('a_package/example:\n' - ' Missing Gradle coverage') - ])); + output, + containsAllInOrder([ + contains('Missing Gradle coverage.'), + contains( + 'Add a "gradle" entry to .github/dependabot.yml for /packages/a_package/example/android/app', + ), + contains( + 'a_package/example:\n' + ' Missing Gradle coverage', + ), + ]), + ); }); test('fails for plugin missing Gradle coverage', () async { @@ -111,52 +128,35 @@ $gradleEntries Error? commandError; final List output = await runCapturingPrint( - runner, ['dependabot-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['dependabot-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Missing Gradle coverage.'), - contains( - 'Add a "gradle" entry to .github/dependabot.yml for /packages/a_plugin/android'), - contains('a_plugin:\n' - ' Missing Gradle coverage') - ])); + output, + containsAllInOrder([ + contains('Missing Gradle coverage.'), + contains( + 'Add a "gradle" entry to .github/dependabot.yml for /packages/a_plugin/android', + ), + contains( + 'a_plugin:\n' + ' Missing Gradle coverage', + ), + ]), + ); }); test('passes for correct Gradle coverage with single directory', () async { - setDependabotCoverage(gradleDirs: [ - 'packages/a_plugin/android', - 'packages/a_plugin/example/android/app', - ]); - final RepositoryPackage plugin = createFakePlugin('a_plugin', packagesDir); - // Test the plugin. - plugin.directory.childDirectory('android').createSync(recursive: true); - // And its example app. - plugin.directory - .childDirectory('example') - .childDirectory('android') - .childDirectory('app') - .createSync(recursive: true); - - final List output = - await runCapturingPrint(runner, ['dependabot-check']); - - expect(output, - containsAllInOrder([contains('Ran for 2 package(s)')])); - }); - - test('passes for correct Gradle coverage with multiple directories', - () async { setDependabotCoverage( gradleDirs: [ 'packages/a_plugin/android', 'packages/a_plugin/example/android/app', ], - useDirectoriesKey: true, ); final RepositoryPackage plugin = createFakePlugin('a_plugin', packagesDir); // Test the plugin. @@ -168,10 +168,47 @@ $gradleEntries .childDirectory('app') .createSync(recursive: true); - final List output = - await runCapturingPrint(runner, ['dependabot-check']); + final List output = await runCapturingPrint(runner, [ + 'dependabot-check', + ]); - expect(output, - containsAllInOrder([contains('Ran for 2 package(s)')])); + expect( + output, + containsAllInOrder([contains('Ran for 2 package(s)')]), + ); }); + + test( + 'passes for correct Gradle coverage with multiple directories', + () async { + setDependabotCoverage( + gradleDirs: [ + 'packages/a_plugin/android', + 'packages/a_plugin/example/android/app', + ], + useDirectoriesKey: true, + ); + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + ); + // Test the plugin. + plugin.directory.childDirectory('android').createSync(recursive: true); + // And its example app. + plugin.directory + .childDirectory('example') + .childDirectory('android') + .childDirectory('app') + .createSync(recursive: true); + + final List output = await runCapturingPrint(runner, [ + 'dependabot-check', + ]); + + expect( + output, + containsAllInOrder([contains('Ran for 2 package(s)')]), + ); + }, + ); } diff --git a/script/tool/test/drive_examples_command_test.dart b/script/tool/test/drive_examples_command_test.dart index a5d596a93683..e9d1cc2e0826 100644 --- a/script/tool/test/drive_examples_command_test.dart +++ b/script/tool/test/drive_examples_command_test.dart @@ -35,7 +35,7 @@ void main() { final GitDir gitDir; (:packagesDir, :processRunner, :gitProcessRunner, :gitDir) = configureBaseCommandMocks(platform: mockPlatform); - final DriveExamplesCommand command = DriveExamplesCommand( + final command = DriveExamplesCommand( packagesDir, processRunner: processRunner, platform: mockPlatform, @@ -43,7 +43,9 @@ void main() { ); runner = CommandRunner( - 'drive_examples_command', 'Test for drive_example_command'); + 'drive_examples_command', + 'Test for drive_example_command', + ); runner.addCommand(command); // TODO(dit): Clean this up, https://github.com/flutter/flutter/issues/151869 @@ -56,27 +58,29 @@ void main() { bool hasAndroidDevice = true, bool includeBanner = false, }) { - const String updateBanner = ''' + const updateBanner = ''' ╔════════════════════════════════════════════════════════════════════════════╗ ║ A new version of Flutter is available! ║ ║ ║ ║ To update to the latest version, run "flutter upgrade". ║ ╚════════════════════════════════════════════════════════════════════════════╝ '''; - final List devices = [ + final devices = [ if (hasIOSDevice) '{"id": "$_fakeIOSDevice", "targetPlatform": "ios"}', if (hasAndroidDevice) '{"id": "$_fakeAndroidDevice", "targetPlatform": "android-x64"}', ]; - final String output = + final output = '''${includeBanner ? updateBanner : ''}[${devices.join(',')}]'''; - final MockProcess mockDevicesProcess = - MockProcess(stdout: output, stdoutEncoding: utf8); - processRunner - .mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = - [ - FakeProcessInfo(mockDevicesProcess, ['devices']) + final mockDevicesProcess = MockProcess( + stdout: output, + stdoutEncoding: utf8, + ); + processRunner.mockProcessesForExecutable[getFlutterCommand( + mockPlatform, + )] = [ + FakeProcessInfo(mockDevicesProcess, ['devices']), ]; } @@ -84,27 +88,27 @@ void main() { setMockFlutterDevicesOutput(); Error? commandError; final List output = await runCapturingPrint( - runner, ['drive-examples'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['drive-examples'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('Exactly one of'), - ]), - ); + expect(output, containsAllInOrder([contains('Exactly one of')])); }); test('fails if wasm flag is present but not web platform', () async { setMockFlutterDevicesOutput(); Error? commandError; final List output = await runCapturingPrint( - runner, ['drive-examples', '--android', '--wasm'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['drive-examples', '--android', '--wasm'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -119,18 +123,15 @@ void main() { setMockFlutterDevicesOutput(); Error? commandError; final List output = await runCapturingPrint( - runner, ['drive-examples', '--ios', '--macos'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['drive-examples', '--ios', '--macos'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('Exactly one of'), - ]), - ); + expect(output, containsAllInOrder([contains('Exactly one of')])); }); test('fails for iOS if no iOS devices are present', () async { @@ -138,17 +139,15 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['drive-examples', '--ios'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['drive-examples', '--ios'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('No iOS devices'), - ]), - ); + expect(output, containsAllInOrder([contains('No iOS devices')])); }); test('handles flutter tool banners when checking devices', () async { @@ -166,8 +165,10 @@ void main() { ); setMockFlutterDevicesOutput(includeBanner: true); - final List output = - await runCapturingPrint(runner, ['drive-examples', '--ios']); + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + '--ios', + ]); expect( output, @@ -180,79 +181,81 @@ void main() { test('fails for iOS if getting devices fails', () async { // Simulate failure from `flutter devices`. - processRunner - .mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = - [ - FakeProcessInfo(MockProcess(exitCode: 1), ['devices']) + processRunner.mockProcessesForExecutable[getFlutterCommand( + mockPlatform, + )] = [ + FakeProcessInfo(MockProcess(exitCode: 1), ['devices']), ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['drive-examples', '--ios'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['drive-examples', '--ios'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('No iOS devices'), - ]), - ); + expect(output, containsAllInOrder([contains('No iOS devices')])); }); test('fails for Android if no Android devices are present', () async { setMockFlutterDevicesOutput(hasAndroidDevice: false); Error? commandError; final List output = await runCapturingPrint( - runner, ['drive-examples', '--android'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['drive-examples', '--android'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, - containsAllInOrder([ - contains('No Android devices'), - ]), + containsAllInOrder([contains('No Android devices')]), ); }); - test('a plugin without any integration test files is reported as an error', - () async { - setMockFlutterDevicesOutput(); - createFakePlugin( - 'plugin', - packagesDir, - extraFiles: [ - 'example/lib/main.dart', - 'example/android/android.java', - 'example/ios/ios.m', - ], - platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline), - platformIOS: const PlatformDetails(PlatformSupport.inline), - }, - ); + test( + 'a plugin without any integration test files is reported as an error', + () async { + setMockFlutterDevicesOutput(); + createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'example/lib/main.dart', + 'example/android/android.java', + 'example/ios/ios.m', + ], + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); - Error? commandError; - final List output = await runCapturingPrint( - runner, ['drive-examples', '--android'], + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['drive-examples', '--android'], errorHandler: (Error e) { - commandError = e; - }); + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('Running for plugin'), - contains('No driver tests were run (1 example(s) found).'), - contains('No tests ran'), - ]), - ); - }); + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains('Running for plugin'), + contains('No driver tests were run (1 example(s) found).'), + contains('No tests ran'), + ]), + ); + }, + ); test('integration tests using test(...) fail validation', () async { setMockFlutterDevicesOutput(); @@ -281,10 +284,12 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['drive-examples', '--android'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['drive-examples', '--android'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -315,8 +320,10 @@ void main() { final Directory pluginExampleDirectory = getExampleDir(plugin); setMockFlutterDevicesOutput(); - final List output = - await runCapturingPrint(runner, ['drive-examples', '--ios']); + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + '--ios', + ]); expect( output, @@ -327,21 +334,21 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall(getFlutterCommand(mockPlatform), - const ['devices', '--machine'], null), - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '-d', - _fakeIOSDevice, - '--debug-logs-dir=/path/to/logs', - 'integration_test', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'devices', + '--machine', + ], null), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '-d', + _fakeIOSDevice, + '--debug-logs-dir=/path/to/logs', + 'integration_test', + ], pluginExampleDirectory.path), + ]), + ); }); test('handles missing CI debug logs directory', () async { @@ -366,8 +373,10 @@ void main() { final Directory pluginExampleDirectory = getExampleDir(plugin); setMockFlutterDevicesOutput(); - final List output = - await runCapturingPrint(runner, ['drive-examples', '--ios']); + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + '--ios', + ]); expect( output, @@ -378,20 +387,20 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall(getFlutterCommand(mockPlatform), - const ['devices', '--machine'], null), - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '-d', - _fakeIOSDevice, - 'integration_test', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'devices', + '--machine', + ], null), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '-d', + _fakeIOSDevice, + 'integration_test', + ], pluginExampleDirectory.path), + ]), + ); }); test('saves a screenshot if test is taking too long', () async { @@ -409,24 +418,29 @@ void main() { }, ); - final FakeAsync fakeAsync = FakeAsync(); - processRunner.mockProcessesForExecutable['flutter']! - .addAll([ - FakeProcessInfo( + final fakeAsync = FakeAsync(); + processRunner.mockProcessesForExecutable['flutter']!.addAll( + [ + FakeProcessInfo( _FakeDelayingProcess( - delayDuration: const Duration(minutes: 11), - fakeAsync: fakeAsync), - ['test']), - FakeProcessInfo(MockProcess(), ['screenshot']), - ]); + delayDuration: const Duration(minutes: 11), + fakeAsync: fakeAsync, + ), + ['test'], + ), + FakeProcessInfo(MockProcess(), ['screenshot']), + ], + ); final Directory pluginExampleDirectory = getExampleDir(plugin); - List output = []; + var output = []; fakeAsync.run((_) { () async { - output = await runCapturingPrint( - runner, ['drive-examples', '--ios']); + output = await runCapturingPrint(runner, [ + 'drive-examples', + '--ios', + ]); }(); }); fakeAsync.flushTimers(); @@ -436,44 +450,42 @@ void main() { containsAllInOrder([ contains('Running for plugin'), contains( - 'Test is taking a long time, taking screenshot test-timeout-screenshot_integration_test.png...'), + 'Test is taking a long time, taking screenshot test-timeout-screenshot_integration_test.png...', + ), contains('No issues found!'), ]), ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall(getFlutterCommand(mockPlatform), - const ['devices', '--machine'], null), - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '-d', - _fakeIOSDevice, - '--debug-logs-dir=/path/to/logs', - 'integration_test', - ], - pluginExampleDirectory.path, - ), - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'screenshot', - '-d', - _fakeIOSDevice, - '--out=/path/to/logs/test-timeout-screenshot_integration_test.png', - ], - pluginExampleDirectory.path, - ), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'devices', + '--machine', + ], null), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '-d', + _fakeIOSDevice, + '--debug-logs-dir=/path/to/logs', + 'integration_test', + ], pluginExampleDirectory.path), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'screenshot', + '-d', + _fakeIOSDevice, + '--out=/path/to/logs/test-timeout-screenshot_integration_test.png', + ], pluginExampleDirectory.path), + ]), + ); }); test('driving when plugin does not support Linux is a no-op', () async { - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/integration_test/plugin_test.dart', - ]); + createFakePlugin( + 'plugin', + packagesDir, + extraFiles: ['example/integration_test/plugin_test.dart'], + ); final List output = await runCapturingPrint(runner, [ 'drive-examples', @@ -523,25 +535,25 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '-d', - 'linux', - '--debug-logs-dir=/path/to/logs', - 'integration_test', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '-d', + 'linux', + '--debug-logs-dir=/path/to/logs', + 'integration_test', + ], pluginExampleDirectory.path), + ]), + ); }); test('driving when plugin does not suppport macOS is a no-op', () async { - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/integration_test/plugin_test.dart', - ]); + createFakePlugin( + 'plugin', + packagesDir, + extraFiles: ['example/integration_test/plugin_test.dart'], + ); final List output = await runCapturingPrint(runner, [ 'drive-examples', @@ -591,19 +603,17 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '-d', - 'macos', - '--debug-logs-dir=/path/to/logs', - 'integration_test', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '-d', + 'macos', + '--debug-logs-dir=/path/to/logs', + 'integration_test', + ], pluginExampleDirectory.path), + ]), + ); }); // This tests the workaround for https://github.com/flutter/flutter/issues/135673 @@ -639,29 +649,24 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '-d', - 'macos', - '--debug-logs-dir=/path/to/logs', - 'integration_test/first_test.dart', - ], - pluginExampleDirectory.path), - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '-d', - 'macos', - '--debug-logs-dir=/path/to/logs', - 'integration_test/second_test.dart', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '-d', + 'macos', + '--debug-logs-dir=/path/to/logs', + 'integration_test/first_test.dart', + ], pluginExampleDirectory.path), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '-d', + 'macos', + '--debug-logs-dir=/path/to/logs', + 'integration_test/second_test.dart', + ], pluginExampleDirectory.path), + ]), + ); }); // This tests the workaround for https://github.com/flutter/flutter/issues/135673 @@ -696,29 +701,24 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '-d', - 'linux', - '--debug-logs-dir=/path/to/logs', - 'integration_test/first_test.dart', - ], - pluginExampleDirectory.path), - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '-d', - 'linux', - '--debug-logs-dir=/path/to/logs', - 'integration_test/second_test.dart', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '-d', + 'linux', + '--debug-logs-dir=/path/to/logs', + 'integration_test/first_test.dart', + ], pluginExampleDirectory.path), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '-d', + 'linux', + '--debug-logs-dir=/path/to/logs', + 'integration_test/second_test.dart', + ], pluginExampleDirectory.path), + ]), + ); }); // This tests the workaround for https://github.com/flutter/flutter/issues/135673 @@ -753,36 +753,33 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '-d', - 'windows', - '--debug-logs-dir=/path/to/logs', - 'integration_test/first_test.dart', - ], - pluginExampleDirectory.path), - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '-d', - 'windows', - '--debug-logs-dir=/path/to/logs', - 'integration_test/second_test.dart', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '-d', + 'windows', + '--debug-logs-dir=/path/to/logs', + 'integration_test/first_test.dart', + ], pluginExampleDirectory.path), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '-d', + 'windows', + '--debug-logs-dir=/path/to/logs', + 'integration_test/second_test.dart', + ], pluginExampleDirectory.path), + ]), + ); }); }); test('driving when plugin does not suppport web is a no-op', () async { - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/integration_test/plugin_test.dart', - ]); + createFakePlugin( + 'plugin', + packagesDir, + extraFiles: ['example/integration_test/plugin_test.dart'], + ); final List output = await runCapturingPrint(runner, [ 'drive-examples', @@ -832,24 +829,22 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'drive', - '-d', - 'web-server', - '--web-port=7357', - '--browser-name=chrome', - '--screenshot=/path/to/logs/plugin_example-drive', - '--driver', - 'test_driver/integration_test.dart', - '--target', - 'integration_test/plugin_test.dart', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'drive', + '-d', + 'web-server', + '--web-port=7357', + '--browser-name=chrome', + '--screenshot=/path/to/logs/plugin_example-drive', + '--driver', + 'test_driver/integration_test.dart', + '--target', + 'integration_test/plugin_test.dart', + ], pluginExampleDirectory.path), + ]), + ); }); test('drives a web plugin compiled to WASM', () async { @@ -883,25 +878,23 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'drive', - '-d', - 'web-server', - '--web-port=7357', - '--browser-name=chrome', - '--wasm', - '--screenshot=/path/to/logs/plugin_example-drive', - '--driver', - 'test_driver/integration_test.dart', - '--target', - 'integration_test/plugin_test.dart', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'drive', + '-d', + 'web-server', + '--web-port=7357', + '--browser-name=chrome', + '--wasm', + '--screenshot=/path/to/logs/plugin_example-drive', + '--driver', + 'test_driver/integration_test.dart', + '--target', + 'integration_test/plugin_test.dart', + ], pluginExampleDirectory.path), + ]), + ); }); test('runs chromedriver when requested', () async { @@ -920,8 +913,11 @@ void main() { final Directory pluginExampleDirectory = getExampleDir(plugin); - final List output = await runCapturingPrint( - runner, ['drive-examples', '--web', '--run-chromedriver']); + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + '--web', + '--run-chromedriver', + ]); expect( output, @@ -932,25 +928,23 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - const ProcessCall('chromedriver', ['--port=4444'], null), - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'drive', - '-d', - 'web-server', - '--web-port=7357', - '--browser-name=chrome', - '--screenshot=/path/to/logs/plugin_example-drive', - '--driver', - 'test_driver/integration_test.dart', - '--target', - 'integration_test/plugin_test.dart', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + const ProcessCall('chromedriver', ['--port=4444'], null), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'drive', + '-d', + 'web-server', + '--web-port=7357', + '--browser-name=chrome', + '--screenshot=/path/to/logs/plugin_example-drive', + '--driver', + 'test_driver/integration_test.dart', + '--target', + 'integration_test/plugin_test.dart', + ], pluginExampleDirectory.path), + ]), + ); }); test('drives a web plugin with CHROME_EXECUTABLE', () async { @@ -985,31 +979,31 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'drive', - '-d', - 'web-server', - '--web-port=7357', - '--browser-name=chrome', - '--chrome-binary=/path/to/chrome', - '--screenshot=/path/to/logs/plugin_example-drive', - '--driver', - 'test_driver/integration_test.dart', - '--target', - 'integration_test/plugin_test.dart', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'drive', + '-d', + 'web-server', + '--web-port=7357', + '--browser-name=chrome', + '--chrome-binary=/path/to/chrome', + '--screenshot=/path/to/logs/plugin_example-drive', + '--driver', + 'test_driver/integration_test.dart', + '--target', + 'integration_test/plugin_test.dart', + ], pluginExampleDirectory.path), + ]), + ); }); test('driving when plugin does not suppport Windows is a no-op', () async { - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/integration_test/plugin_test.dart', - ]); + createFakePlugin( + 'plugin', + packagesDir, + extraFiles: ['example/integration_test/plugin_test.dart'], + ); final List output = await runCapturingPrint(runner, [ 'drive-examples', @@ -1059,19 +1053,17 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '-d', - 'windows', - '--debug-logs-dir=/path/to/logs', - 'integration_test', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '-d', + 'windows', + '--debug-logs-dir=/path/to/logs', + 'integration_test', + ], pluginExampleDirectory.path), + ]), + ); }); test('tests an Android plugin', () async { @@ -1104,21 +1096,21 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall(getFlutterCommand(mockPlatform), - const ['devices', '--machine'], null), - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '-d', - _fakeAndroidDevice, - '--debug-logs-dir=/path/to/logs', - 'integration_test', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'devices', + '--machine', + ], null), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '-d', + _fakeAndroidDevice, + '--debug-logs-dir=/path/to/logs', + 'integration_test', + ], pluginExampleDirectory.path), + ]), + ); }); test('tests an Android plugin with "apk" alias', () async { @@ -1151,38 +1143,38 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall(getFlutterCommand(mockPlatform), - const ['devices', '--machine'], null), - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '-d', - _fakeAndroidDevice, - '--debug-logs-dir=/path/to/logs', - 'integration_test', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'devices', + '--machine', + ], null), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '-d', + _fakeAndroidDevice, + '--debug-logs-dir=/path/to/logs', + 'integration_test', + ], pluginExampleDirectory.path), + ]), + ); }); test('driving when plugin does not support Android is no-op', () async { createFakePlugin( 'plugin', packagesDir, - extraFiles: [ - 'example/integration_test/plugin_test.dart', - ], + extraFiles: ['example/integration_test/plugin_test.dart'], platformSupport: { platformMacOS: const PlatformDetails(PlatformSupport.inline), }, ); setMockFlutterDevicesOutput(); - final List output = await runCapturingPrint( - runner, ['drive-examples', '--android']); + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + '--android', + ]); expect( output, @@ -1195,8 +1187,10 @@ void main() { // Output should be empty other than the device query. expect(processRunner.recordedCalls, [ - ProcessCall(getFlutterCommand(mockPlatform), - const ['devices', '--machine'], null), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'devices', + '--machine', + ], null), ]); }); @@ -1204,17 +1198,17 @@ void main() { createFakePlugin( 'plugin', packagesDir, - extraFiles: [ - 'example/integration_test/plugin_test.dart', - ], + extraFiles: ['example/integration_test/plugin_test.dart'], platformSupport: { platformMacOS: const PlatformDetails(PlatformSupport.inline), }, ); setMockFlutterDevicesOutput(); - final List output = - await runCapturingPrint(runner, ['drive-examples', '--ios']); + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + '--ios', + ]); expect( output, @@ -1227,25 +1221,33 @@ void main() { // Output should be empty other than the device query. expect(processRunner.recordedCalls, [ - ProcessCall(getFlutterCommand(mockPlatform), - const ['devices', '--machine'], null), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'devices', + '--machine', + ], null), ]); }); test('platform interface plugins are silently skipped', () async { - createFakePlugin('aplugin_platform_interface', packagesDir, - examples: []); + createFakePlugin( + 'aplugin_platform_interface', + packagesDir, + examples: [], + ); setMockFlutterDevicesOutput(); - final List output = await runCapturingPrint( - runner, ['drive-examples', '--macos']); + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + '--macos', + ]); expect( output, containsAllInOrder([ contains('Running for aplugin_platform_interface'), contains( - 'SKIPPING: Platform interfaces are not expected to have integration tests.'), + 'SKIPPING: Platform interfaces are not expected to have integration tests.', + ), contains('No issues found!'), ]), ); @@ -1279,22 +1281,22 @@ void main() { ]); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall(getFlutterCommand(mockPlatform), - const ['devices', '--machine'], null), - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '-d', - _fakeIOSDevice, - '--enable-experiment=exp1', - '--debug-logs-dir=/path/to/logs', - 'integration_test', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'devices', + '--machine', + ], null), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '-d', + _fakeIOSDevice, + '--enable-experiment=exp1', + '--debug-logs-dir=/path/to/logs', + 'integration_test', + ], pluginExampleDirectory.path), + ]), + ); }); test('fails when no example is present', () async { @@ -1309,9 +1311,12 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['drive-examples', '--web'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['drive-examples', '--web'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -1320,8 +1325,10 @@ void main() { contains('Running for plugin'), contains('No driver tests were run (0 example(s) found).'), contains('The following packages had errors:'), - contains(' plugin:\n' - ' No tests ran (use --exclude if this is intentional)'), + contains( + ' plugin:\n' + ' No tests ran (use --exclude if this is intentional)', + ), ]), ); }); @@ -1342,9 +1349,12 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['drive-examples', '--web'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['drive-examples', '--web'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -1354,8 +1364,10 @@ void main() { contains('No driver found for plugin/example'), contains('No driver tests were run (1 example(s) found).'), contains('The following packages had errors:'), - contains(' plugin:\n' - ' No tests ran (use --exclude if this is intentional)'), + contains( + ' plugin:\n' + ' No tests ran (use --exclude if this is intentional)', + ), ]), ); }); @@ -1375,9 +1387,12 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['drive-examples', '--web'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['drive-examples', '--web'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -1386,8 +1401,10 @@ void main() { contains('Running for plugin'), contains('No driver tests were run (1 example(s) found).'), contains('The following packages had errors:'), - contains(' plugin:\n' - ' No tests ran (use --exclude if this is intentional)'), + contains( + ' plugin:\n' + ' No tests ran (use --exclude if this is intentional)', + ), ]), ); }); @@ -1408,9 +1425,9 @@ void main() { ); // Simulate failure from `flutter drive`. - processRunner - .mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = - [ + processRunner.mockProcessesForExecutable[getFlutterCommand( + mockPlatform, + )] = [ // Fail both bar_test.dart and foo_test.dart. FakeProcessInfo(MockProcess(exitCode: 1), ['drive']), FakeProcessInfo(MockProcess(exitCode: 1), ['drive']), @@ -1418,9 +1435,12 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['drive-examples', '--web'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['drive-examples', '--web'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -1428,47 +1448,44 @@ void main() { containsAllInOrder([ contains('Running for plugin'), contains('The following packages had errors:'), - contains(' plugin:\n' - ' example/integration_test/bar_test.dart\n' - ' example/integration_test/foo_test.dart'), + contains( + ' plugin:\n' + ' example/integration_test/bar_test.dart\n' + ' example/integration_test/foo_test.dart', + ), ]), ); final Directory pluginExampleDirectory = getExampleDir(plugin); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'drive', - '-d', - 'web-server', - '--web-port=7357', - '--browser-name=chrome', - '--screenshot=/path/to/logs/plugin_example-drive', - '--driver', - 'test_driver/integration_test.dart', - '--target', - 'integration_test/bar_test.dart', - ], - pluginExampleDirectory.path), - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'drive', - '-d', - 'web-server', - '--web-port=7357', - '--browser-name=chrome', - '--screenshot=/path/to/logs/plugin_example-drive', - '--driver', - 'test_driver/integration_test.dart', - '--target', - 'integration_test/foo_test.dart', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'drive', + '-d', + 'web-server', + '--web-port=7357', + '--browser-name=chrome', + '--screenshot=/path/to/logs/plugin_example-drive', + '--driver', + 'test_driver/integration_test.dart', + '--target', + 'integration_test/bar_test.dart', + ], pluginExampleDirectory.path), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'drive', + '-d', + 'web-server', + '--web-port=7357', + '--browser-name=chrome', + '--screenshot=/path/to/logs/plugin_example-drive', + '--driver', + 'test_driver/integration_test.dart', + '--target', + 'integration_test/foo_test.dart', + ], pluginExampleDirectory.path), + ]), + ); }); test('"flutter test" reports test failures', () async { @@ -1492,9 +1509,12 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['drive-examples', '--ios'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['drive-examples', '--ios'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -1502,38 +1522,43 @@ void main() { containsAllInOrder([ contains('Running for plugin'), contains('The following packages had errors:'), - contains(' plugin:\n' - ' Integration tests failed.'), + contains( + ' plugin:\n' + ' Integration tests failed.', + ), ]), ); final Directory pluginExampleDirectory = getExampleDir(plugin); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall(getFlutterCommand(mockPlatform), - const ['devices', '--machine'], null), - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'test', - '-d', - _fakeIOSDevice, - '--debug-logs-dir=/path/to/logs', - 'integration_test', - ], - pluginExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'devices', + '--machine', + ], null), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'test', + '-d', + _fakeIOSDevice, + '--debug-logs-dir=/path/to/logs', + 'integration_test', + ], pluginExampleDirectory.path), + ]), + ); }); group('packages', () { test('can be driven', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, extraFiles: [ - 'example/integration_test/foo_test.dart', - 'example/test_driver/integration_test.dart', - 'example/web/index.html', - ]); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + extraFiles: [ + 'example/integration_test/foo_test.dart', + 'example/test_driver/integration_test.dart', + 'example/web/index.html', + ], + ); final Directory exampleDirectory = getExampleDir(package); final List output = await runCapturingPrint(runner, [ @@ -1550,35 +1575,36 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'drive', - '-d', - 'web-server', - '--web-port=7357', - '--browser-name=chrome', - '--screenshot=/path/to/logs/a_package_example-drive', - '--driver', - 'test_driver/integration_test.dart', - '--target', - 'integration_test/foo_test.dart' - ], - exampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'drive', + '-d', + 'web-server', + '--web-port=7357', + '--browser-name=chrome', + '--screenshot=/path/to/logs/a_package_example-drive', + '--driver', + 'test_driver/integration_test.dart', + '--target', + 'integration_test/foo_test.dart', + ], exampleDirectory.path), + ]), + ); }); test('drive handles missing CI screenshot directory', () async { mockPlatform.environment.remove('FLUTTER_LOGS_DIR'); - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, extraFiles: [ - 'example/integration_test/foo_test.dart', - 'example/test_driver/integration_test.dart', - 'example/web/index.html', - ]); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + extraFiles: [ + 'example/integration_test/foo_test.dart', + 'example/test_driver/integration_test.dart', + 'example/web/index.html', + ], + ); final Directory exampleDirectory = getExampleDir(package); final List output = await runCapturingPrint(runner, [ @@ -1595,32 +1621,33 @@ void main() { ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'drive', - '-d', - 'web-server', - '--web-port=7357', - '--browser-name=chrome', - '--driver', - 'test_driver/integration_test.dart', - '--target', - 'integration_test/foo_test.dart' - ], - exampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'drive', + '-d', + 'web-server', + '--web-port=7357', + '--browser-name=chrome', + '--driver', + 'test_driver/integration_test.dart', + '--target', + 'integration_test/foo_test.dart', + ], exampleDirectory.path), + ]), + ); }); test('are skipped when example does not support platform', () async { - createFakePackage('a_package', packagesDir, - isFlutter: true, - extraFiles: [ - 'example/integration_test/foo_test.dart', - 'example/test_driver/integration_test.dart', - ]); + createFakePackage( + 'a_package', + packagesDir, + isFlutter: true, + extraFiles: [ + 'example/integration_test/foo_test.dart', + 'example/test_driver/integration_test.dart', + ], + ); final List output = await runCapturingPrint(runner, [ 'drive-examples', @@ -1631,8 +1658,10 @@ void main() { output, containsAllInOrder([ contains('Running for a_package'), - contains('Skipping a_package/example; does not support any ' - 'requested platforms'), + contains( + 'Skipping a_package/example; does not support any ' + 'requested platforms', + ), contains('SKIPPING: No example supports requested platform(s).'), ]), ); @@ -1642,21 +1671,21 @@ void main() { test('drive only supported examples if there is more than one', () async { final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - isFlutter: true, - examples: [ - 'with_web', - 'without_web' - ], - extraFiles: [ - 'example/with_web/integration_test/foo_test.dart', - 'example/with_web/test_driver/integration_test.dart', - 'example/with_web/web/index.html', - 'example/without_web/integration_test/foo_test.dart', - 'example/without_web/test_driver/integration_test.dart', - ]); - final Directory supportedExampleDirectory = - getExampleDir(package).childDirectory('with_web'); + 'a_package', + packagesDir, + isFlutter: true, + examples: ['with_web', 'without_web'], + extraFiles: [ + 'example/with_web/integration_test/foo_test.dart', + 'example/with_web/test_driver/integration_test.dart', + 'example/with_web/web/index.html', + 'example/without_web/integration_test/foo_test.dart', + 'example/without_web/test_driver/integration_test.dart', + ], + ); + final Directory supportedExampleDirectory = getExampleDir( + package, + ).childDirectory('with_web'); final List output = await runCapturingPrint(runner, [ 'drive-examples', @@ -1668,35 +1697,38 @@ void main() { containsAllInOrder([ contains('Running for a_package'), contains( - 'Skipping a_package/example/without_web; does not support any requested platforms.'), + 'Skipping a_package/example/without_web; does not support any requested platforms.', + ), contains('No issues found!'), ]), ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'drive', - '-d', - 'web-server', - '--web-port=7357', - '--browser-name=chrome', - '--screenshot=/path/to/logs/a_package_example_with_web-drive', - '--driver', - 'test_driver/integration_test.dart', - '--target', - 'integration_test/foo_test.dart' - ], - supportedExampleDirectory.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'drive', + '-d', + 'web-server', + '--web-port=7357', + '--browser-name=chrome', + '--screenshot=/path/to/logs/a_package_example_with_web-drive', + '--driver', + 'test_driver/integration_test.dart', + '--target', + 'integration_test/foo_test.dart', + ], supportedExampleDirectory.path), + ]), + ); }); test('are skipped when there is no integration testing', () async { - createFakePackage('a_package', packagesDir, - isFlutter: true, extraFiles: ['example/web/index.html']); + createFakePackage( + 'a_package', + packagesDir, + isFlutter: true, + extraFiles: ['example/web/index.html'], + ); final List output = await runCapturingPrint(runner, [ 'drive-examples', @@ -1708,7 +1740,8 @@ void main() { containsAllInOrder([ contains('Running for a_package'), contains( - 'SKIPPING: No example is configured for integration tests.'), + 'SKIPPING: No example is configured for integration tests.', + ), ]), ); @@ -1717,7 +1750,7 @@ void main() { }); group('file filtering', () { - const List files = [ + const files = [ 'pubspec.yaml', 'foo.dart', 'foo.java', @@ -1728,30 +1761,36 @@ void main() { 'foo.cpp', 'foo.h', ]; - for (final String file in files) { + for (final file in files) { test('runs command for changes to $file', () async { createFakePackage('package_a', packagesDir); gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: + ''' packages/package_a/$file -''')), - ]; +''', + ), + ), + ]; // The target platform is irrelevant here; because this repo's // packages are fully federated, there's no need to distinguish // the ignore list by target (e.g., skipping iOS tests if only Java or // Kotlin files change), because package-level filering will already // accomplish the same goal. - final List output = await runCapturingPrint( - runner, ['drive-examples', '--web']); + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + '--web', + ]); expect( - output, - containsAllInOrder([ - contains('Running for package_a'), - ])); + output, + containsAllInOrder([contains('Running for package_a')]), + ); }); } @@ -1760,27 +1799,32 @@ packages/package_a/$file gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' README.md CODEOWNERS .gitignore packages/package_a/CHANGELOG.md -''')), - ]; +''', + ), + ), + ]; - final List output = - await runCapturingPrint(runner, ['drive-examples']); + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + ]); expect( - output, - isNot(containsAllInOrder([ - contains('Running for package_a'), - ]))); + output, + isNot( + containsAllInOrder([contains('Running for package_a')]), + ), + ); expect( - output, - containsAllInOrder([ - contains('SKIPPING ALL PACKAGES'), - ])); + output, + containsAllInOrder([contains('SKIPPING ALL PACKAGES')]), + ); }); }); }); @@ -1788,10 +1832,11 @@ packages/package_a/CHANGELOG.md class _FakeDelayingProcess extends Fake implements io.Process { /// Creates a mock process that takes [delayDuration] time to exit successfully. - _FakeDelayingProcess( - {required Duration delayDuration, required FakeAsync fakeAsync}) - : _delayDuration = delayDuration, - _fakeAsync = fakeAsync; + _FakeDelayingProcess({ + required Duration delayDuration, + required FakeAsync fakeAsync, + }) : _delayDuration = delayDuration, + _fakeAsync = fakeAsync; final Duration _delayDuration; final FakeAsync _fakeAsync; diff --git a/script/tool/test/federation_safety_check_command_test.dart b/script/tool/test/federation_safety_check_command_test.dart index 88c7740811bd..b88180b62799 100644 --- a/script/tool/test/federation_safety_check_command_test.dart +++ b/script/tool/test/federation_safety_check_command_test.dart @@ -25,14 +25,17 @@ void main() { (:packagesDir, :processRunner, :gitProcessRunner, :gitDir) = configureBaseCommandMocks(platform: mockPlatform); - final FederationSafetyCheckCommand command = FederationSafetyCheckCommand( - packagesDir, - processRunner: processRunner, - platform: mockPlatform, - gitDir: gitDir); - - runner = CommandRunner('federation_safety_check_command', - 'Test for $FederationSafetyCheckCommand'); + final command = FederationSafetyCheckCommand( + packagesDir, + processRunner: processRunner, + platform: mockPlatform, + gitDir: gitDir, + ); + + runner = CommandRunner( + 'federation_safety_check_command', + 'Test for $FederationSafetyCheckCommand', + ); runner.addCommand(command); }); @@ -46,8 +49,9 @@ void main() { FakeProcessInfo(MockProcess(stdout: changedFileOutput)), ]; - final List output = - await runCapturingPrint(runner, ['federation-safety-check']); + final List output = await runCapturingPrint(runner, [ + 'federation-safety-check', + ]); expect( output, @@ -69,8 +73,9 @@ void main() { FakeProcessInfo(MockProcess(stdout: changedFileOutput)), ]; - final List output = - await runCapturingPrint(runner, ['federation-safety-check']); + final List output = await runCapturingPrint(runner, [ + 'federation-safety-check', + ]); expect( output, @@ -84,8 +89,10 @@ void main() { test('skips interface packages', () async { final Directory pluginGroupDir = packagesDir.childDirectory('foo'); - final RepositoryPackage platformInterface = - createFakePlugin('foo_platform_interface', pluginGroupDir); + final RepositoryPackage platformInterface = createFakePlugin( + 'foo_platform_interface', + pluginGroupDir, + ); final String changedFileOutput = [ platformInterface.libDirectory.childFile('foo.dart'), @@ -94,8 +101,9 @@ void main() { FakeProcessInfo(MockProcess(stdout: changedFileOutput)), ]; - final List output = - await runCapturingPrint(runner, ['federation-safety-check']); + final List output = await runCapturingPrint(runner, [ + 'federation-safety-check', + ]); expect( output, @@ -109,8 +117,10 @@ void main() { test('allows changes to just an interface package', () async { final Directory pluginGroupDir = packagesDir.childDirectory('foo'); - final RepositoryPackage platformInterface = - createFakePlugin('foo_platform_interface', pluginGroupDir); + final RepositoryPackage platformInterface = createFakePlugin( + 'foo_platform_interface', + pluginGroupDir, + ); createFakePlugin('foo', pluginGroupDir); createFakePlugin('foo_ios', pluginGroupDir); createFakePlugin('foo_android', pluginGroupDir); @@ -123,8 +133,9 @@ void main() { FakeProcessInfo(MockProcess(stdout: changedFileOutput)), ]; - final List output = - await runCapturingPrint(runner, ['federation-safety-check']); + final List output = await runCapturingPrint(runner, [ + 'federation-safety-check', + ]); expect( output, @@ -142,17 +153,21 @@ void main() { ); expect( output, - isNot(contains([ - contains('No published changes for foo_platform_interface'), - ])), + isNot( + contains([ + contains('No published changes for foo_platform_interface'), + ]), + ), ); }); test('allows changes to multiple non-interface packages', () async { final Directory pluginGroupDir = packagesDir.childDirectory('foo'); final RepositoryPackage appFacing = createFakePlugin('foo', pluginGroupDir); - final RepositoryPackage implementation = - createFakePlugin('foo_bar', pluginGroupDir); + final RepositoryPackage implementation = createFakePlugin( + 'foo_bar', + pluginGroupDir, + ); createFakePlugin('foo_platform_interface', pluginGroupDir); final String changedFileOutput = [ @@ -163,8 +178,9 @@ void main() { FakeProcessInfo(MockProcess(stdout: changedFileOutput)), ]; - final List output = - await runCapturingPrint(runner, ['federation-safety-check']); + final List output = await runCapturingPrint(runner, [ + 'federation-safety-check', + ]); expect( output, @@ -178,16 +194,23 @@ void main() { }); test( - 'fails on changes to interface and non-interface packages in the same plugin', - () async { - final Directory pluginGroupDir = packagesDir.childDirectory('foo'); - final RepositoryPackage appFacing = createFakePlugin('foo', pluginGroupDir); - final RepositoryPackage implementation = - createFakePlugin('foo_bar', pluginGroupDir); - final RepositoryPackage platformInterface = - createFakePlugin('foo_platform_interface', pluginGroupDir); - - const String appFacingChanges = ''' + 'fails on changes to interface and non-interface packages in the same plugin', + () async { + final Directory pluginGroupDir = packagesDir.childDirectory('foo'); + final RepositoryPackage appFacing = createFakePlugin( + 'foo', + pluginGroupDir, + ); + final RepositoryPackage implementation = createFakePlugin( + 'foo_bar', + pluginGroupDir, + ); + final RepositoryPackage platformInterface = createFakePlugin( + 'foo_platform_interface', + pluginGroupDir, + ); + + const appFacingChanges = ''' diff --git a/packages/foo/foo/lib/foo.dart b/packages/foo/foo/lib/foo.dart index abc123..def456 100644 --- a/packages/foo/foo/lib/foo.dart @@ -204,61 +227,84 @@ index abc123..def456 100644 // Do things. '''; - final String changedFileOutput = [ - appFacing.libDirectory.childFile('foo.dart'), - implementation.libDirectory.childFile('foo.dart'), - platformInterface.pubspecFile, - platformInterface.libDirectory.childFile('foo.dart'), - ].map((File file) => file.path).join('\n'); - gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: changedFileOutput)), - // Ensure that a change with both a comment and non-comment addition is - // counted, to validate change analysis. - FakeProcessInfo(MockProcess(stdout: appFacingChanges), - ['', 'HEAD', '--', '/packages/foo/foo/lib/foo.dart']), - // The others diffs don't need to be specified, since empty diff is also - // treated as a non-comment change. - ]; - - Error? commandError; - final List output = await runCapturingPrint( - runner, ['federation-safety-check'], errorHandler: (Error e) { - commandError = e; - }); - - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('Running for foo/foo...'), - contains('Dart changes are not allowed to other packages in foo in the ' + final String changedFileOutput = [ + appFacing.libDirectory.childFile('foo.dart'), + implementation.libDirectory.childFile('foo.dart'), + platformInterface.pubspecFile, + platformInterface.libDirectory.childFile('foo.dart'), + ].map((File file) => file.path).join('\n'); + gitProcessRunner + .mockProcessesForExecutable['git-diff'] = [ + FakeProcessInfo(MockProcess(stdout: changedFileOutput)), + // Ensure that a change with both a comment and non-comment addition is + // counted, to validate change analysis. + FakeProcessInfo(MockProcess(stdout: appFacingChanges), [ + '', + 'HEAD', + '--', + '/packages/foo/foo/lib/foo.dart', + ]), + // The others diffs don't need to be specified, since empty diff is also + // treated as a non-comment change. + ]; + + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['federation-safety-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); + + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains('Running for foo/foo...'), + contains( + 'Dart changes are not allowed to other packages in foo in the ' 'same PR as changes to public Dart code in foo_platform_interface, ' 'as this can cause accidental breaking changes to be missed by ' 'automated checks. Please split the changes to these two packages ' - 'into separate PRs.'), - contains('Running for foo_bar...'), - contains('Dart changes are not allowed to other packages in foo'), - contains('The following packages had errors:'), - contains('foo/foo:\n' - ' foo_platform_interface changed.'), - contains('foo_bar:\n' - ' foo_platform_interface changed.'), - ]), - ); - }); + 'into separate PRs.', + ), + contains('Running for foo_bar...'), + contains('Dart changes are not allowed to other packages in foo'), + contains('The following packages had errors:'), + contains( + 'foo/foo:\n' + ' foo_platform_interface changed.', + ), + contains( + 'foo_bar:\n' + ' foo_platform_interface changed.', + ), + ]), + ); + }, + ); - test('fails with specific text for combo PRs using the recommended tooling', - () async { - final Directory pluginGroupDir = packagesDir.childDirectory('foo'); - final RepositoryPackage appFacing = createFakePlugin('foo', pluginGroupDir); - final RepositoryPackage implementation = - createFakePlugin('foo_bar', pluginGroupDir); - final RepositoryPackage platformInterface = - createFakePlugin('foo_platform_interface', pluginGroupDir); - - void addFakeTempPubspecOverrides(RepositoryPackage package) { - final String contents = package.pubspecFile.readAsStringSync(); - package.pubspecFile.writeAsStringSync(''' + test( + 'fails with specific text for combo PRs using the recommended tooling', + () async { + final Directory pluginGroupDir = packagesDir.childDirectory('foo'); + final RepositoryPackage appFacing = createFakePlugin( + 'foo', + pluginGroupDir, + ); + final RepositoryPackage implementation = createFakePlugin( + 'foo_bar', + pluginGroupDir, + ); + final RepositoryPackage platformInterface = createFakePlugin( + 'foo_platform_interface', + pluginGroupDir, + ); + + void addFakeTempPubspecOverrides(RepositoryPackage package) { + final String contents = package.pubspecFile.readAsStringSync(); + package.pubspecFile.writeAsStringSync(''' $contents # FOR TESTING AND INITIAL REVIEW ONLY. $kDoNotLandWarning. @@ -266,12 +312,12 @@ dependency_overrides: foo_platform_interface: path: ../../../foo/foo_platform_interface '''); - } + } - addFakeTempPubspecOverrides(appFacing.getExamples().first); - addFakeTempPubspecOverrides(implementation.getExamples().first); + addFakeTempPubspecOverrides(appFacing.getExamples().first); + addFakeTempPubspecOverrides(implementation.getExamples().first); - const String appFacingChanges = ''' + const appFacingChanges = ''' diff --git a/packages/foo/foo/lib/foo.dart b/packages/foo/foo/lib/foo.dart index abc123..def456 100644 --- a/packages/foo/foo/lib/foo.dart @@ -288,55 +334,74 @@ index abc123..def456 100644 // Do things. '''; - final String changedFileOutput = [ - appFacing.libDirectory.childFile('foo.dart'), - implementation.libDirectory.childFile('foo.dart'), - platformInterface.pubspecFile, - platformInterface.libDirectory.childFile('foo.dart'), - ].map((File file) => file.path).join('\n'); - gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: changedFileOutput)), - FakeProcessInfo(MockProcess(stdout: appFacingChanges), - ['', 'HEAD', '--', '/packages/foo/foo/lib/foo.dart']), - // The others diffs don't need to be specified, since empty diff is also - // treated as a non-comment change. - ]; - - Error? commandError; - final List output = await runCapturingPrint( - runner, ['federation-safety-check'], errorHandler: (Error e) { - commandError = e; - }); - - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('Running for foo/foo...'), - contains('"DO NOT MERGE" found in pubspec.yaml, so this is assumed to ' + final String changedFileOutput = [ + appFacing.libDirectory.childFile('foo.dart'), + implementation.libDirectory.childFile('foo.dart'), + platformInterface.pubspecFile, + platformInterface.libDirectory.childFile('foo.dart'), + ].map((File file) => file.path).join('\n'); + gitProcessRunner + .mockProcessesForExecutable['git-diff'] = [ + FakeProcessInfo(MockProcess(stdout: changedFileOutput)), + FakeProcessInfo(MockProcess(stdout: appFacingChanges), [ + '', + 'HEAD', + '--', + '/packages/foo/foo/lib/foo.dart', + ]), + // The others diffs don't need to be specified, since empty diff is also + // treated as a non-comment change. + ]; + + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['federation-safety-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); + + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains('Running for foo/foo...'), + contains( + '"DO NOT MERGE" found in pubspec.yaml, so this is assumed to ' 'be the initial combination PR for a federated change, following ' 'the standard repository procedure. This failure is expected, in ' 'order to prevent accidentally landing the temporary overrides, ' 'and will automatically be resolved when the temporary overrides ' - 'are replaced by dependency version bumps later in the process.'), - contains('Running for foo_bar...'), - contains('"DO NOT MERGE" found in pubspec.yaml'), - contains('The following packages had errors:'), - contains('foo/foo:\n' - ' Unresolved combo PR.'), - contains('foo_bar:\n' - ' Unresolved combo PR.'), - ]), - ); - }); + 'are replaced by dependency version bumps later in the process.', + ), + contains('Running for foo_bar...'), + contains('"DO NOT MERGE" found in pubspec.yaml'), + contains('The following packages had errors:'), + contains( + 'foo/foo:\n' + ' Unresolved combo PR.', + ), + contains( + 'foo_bar:\n' + ' Unresolved combo PR.', + ), + ]), + ); + }, + ); test('ignores test-only changes to interface packages', () async { final Directory pluginGroupDir = packagesDir.childDirectory('foo'); final RepositoryPackage appFacing = createFakePlugin('foo', pluginGroupDir); - final RepositoryPackage implementation = - createFakePlugin('foo_bar', pluginGroupDir); - final RepositoryPackage platformInterface = - createFakePlugin('foo_platform_interface', pluginGroupDir); + final RepositoryPackage implementation = createFakePlugin( + 'foo_bar', + pluginGroupDir, + ); + final RepositoryPackage platformInterface = createFakePlugin( + 'foo_platform_interface', + pluginGroupDir, + ); final String changedFileOutput = [ appFacing.libDirectory.childFile('foo.dart'), @@ -348,8 +413,9 @@ index abc123..def456 100644 FakeProcessInfo(MockProcess(stdout: changedFileOutput)), ]; - final List output = - await runCapturingPrint(runner, ['federation-safety-check']); + final List output = await runCapturingPrint(runner, [ + 'federation-safety-check', + ]); expect( output, @@ -365,10 +431,14 @@ index abc123..def456 100644 test('ignores unpublished changes to interface packages', () async { final Directory pluginGroupDir = packagesDir.childDirectory('foo'); final RepositoryPackage appFacing = createFakePlugin('foo', pluginGroupDir); - final RepositoryPackage implementation = - createFakePlugin('foo_bar', pluginGroupDir); - final RepositoryPackage platformInterface = - createFakePlugin('foo_platform_interface', pluginGroupDir); + final RepositoryPackage implementation = createFakePlugin( + 'foo_bar', + pluginGroupDir, + ); + final RepositoryPackage platformInterface = createFakePlugin( + 'foo_platform_interface', + pluginGroupDir, + ); final String changedFileOutput = [ appFacing.libDirectory.childFile('foo.dart'), @@ -381,12 +451,14 @@ index abc123..def456 100644 ]; // Simulate no change to the version in the interface's pubspec.yaml. gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess( - stdout: platformInterface.pubspecFile.readAsStringSync())), + FakeProcessInfo( + MockProcess(stdout: platformInterface.pubspecFile.readAsStringSync()), + ), ]; - final List output = - await runCapturingPrint(runner, ['federation-safety-check']); + final List output = await runCapturingPrint(runner, [ + 'federation-safety-check', + ]); expect( output, @@ -401,10 +473,14 @@ index abc123..def456 100644 test('ignores comment-only changes in implementation packages', () async { final Directory pluginGroupDir = packagesDir.childDirectory('foo'); - final RepositoryPackage implementation = - createFakePlugin('foo_bar', pluginGroupDir); - final RepositoryPackage platformInterface = - createFakePlugin('foo_platform_interface', pluginGroupDir); + final RepositoryPackage implementation = createFakePlugin( + 'foo_bar', + pluginGroupDir, + ); + final RepositoryPackage platformInterface = createFakePlugin( + 'foo_platform_interface', + pluginGroupDir, + ); final String changedFileOutput = [ implementation.libDirectory.childFile('foo.dart'), @@ -412,7 +488,7 @@ index abc123..def456 100644 platformInterface.libDirectory.childFile('foo.dart'), ].map((File file) => file.path).join('\n'); - const String platformInterfaceChanges = ''' + const platformInterfaceChanges = ''' diff --git a/packages/foo/foo_platform_interface/lib/foo.dart b/packages/foo/foo_platform_interface/lib/foo.dart index abc123..def456 100644 --- a/packages/foo/foo_platform_interface/lib/foo.dart @@ -426,7 +502,7 @@ index abc123..def456 100644 e, } '''; - const String implementationChanges = ''' + const implementationChanges = ''' diff --git a/packages/foo/foo_bar/lib/foo.dart b/packages/foo/foo_bar/lib/foo.dart index abc123..def456 100644 --- a/packages/foo/foo_bar/lib/foo.dart @@ -444,20 +520,26 @@ index abc123..def456 100644 '''; gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo( - MockProcess(stdout: changedFileOutput), ['--name-only']), - FakeProcessInfo(MockProcess(stdout: implementationChanges), - ['', 'HEAD', '--', '/packages/foo/foo_bar/lib/foo.dart']), + FakeProcessInfo(MockProcess(stdout: changedFileOutput), [ + '--name-only', + ]), + FakeProcessInfo(MockProcess(stdout: implementationChanges), [ + '', + 'HEAD', + '--', + '/packages/foo/foo_bar/lib/foo.dart', + ]), FakeProcessInfo(MockProcess(stdout: platformInterfaceChanges), [ '', 'HEAD', '--', - '/packages/foo/foo_platform_interface/lib/foo.dart' + '/packages/foo/foo_platform_interface/lib/foo.dart', ]), ]; - final List output = - await runCapturingPrint(runner, ['federation-safety-check']); + final List output = await runCapturingPrint(runner, [ + 'federation-safety-check', + ]); expect( output, @@ -470,10 +552,14 @@ index abc123..def456 100644 test('ignores comment-only changes in platform interface packages', () async { final Directory pluginGroupDir = packagesDir.childDirectory('foo'); - final RepositoryPackage implementation = - createFakePlugin('foo_bar', pluginGroupDir); - final RepositoryPackage platformInterface = - createFakePlugin('foo_platform_interface', pluginGroupDir); + final RepositoryPackage implementation = createFakePlugin( + 'foo_bar', + pluginGroupDir, + ); + final RepositoryPackage platformInterface = createFakePlugin( + 'foo_platform_interface', + pluginGroupDir, + ); final String changedFileOutput = [ implementation.libDirectory.childFile('foo.dart'), @@ -481,7 +567,7 @@ index abc123..def456 100644 platformInterface.libDirectory.childFile('foo.dart'), ].map((File file) => file.path).join('\n'); - const String platformInterfaceChanges = ''' + const platformInterfaceChanges = ''' diff --git a/packages/foo/foo_platform_interface/lib/foo.dart b/packages/foo/foo_platform_interface/lib/foo.dart index abc123..def456 100644 --- a/packages/foo/foo_platform_interface/lib/foo.dart @@ -496,7 +582,7 @@ index abc123..def456 100644 some code; } '''; - const String implementationChanges = ''' + const implementationChanges = ''' diff --git a/packages/foo/foo_bar/lib/foo.dart b/packages/foo/foo_bar/lib/foo.dart index abc123..def456 100644 --- a/packages/foo/foo_bar/lib/foo.dart @@ -512,20 +598,26 @@ index abc123..def456 100644 '''; gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo( - MockProcess(stdout: changedFileOutput), ['--name-only']), - FakeProcessInfo(MockProcess(stdout: implementationChanges), - ['', 'HEAD', '--', '/packages/foo/foo_bar/lib/foo.dart']), + FakeProcessInfo(MockProcess(stdout: changedFileOutput), [ + '--name-only', + ]), + FakeProcessInfo(MockProcess(stdout: implementationChanges), [ + '', + 'HEAD', + '--', + '/packages/foo/foo_bar/lib/foo.dart', + ]), FakeProcessInfo(MockProcess(stdout: platformInterfaceChanges), [ '', 'HEAD', '--', - '/packages/foo/foo_platform_interface/lib/foo.dart' + '/packages/foo/foo_platform_interface/lib/foo.dart', ]), ]; - final List output = - await runCapturingPrint(runner, ['federation-safety-check']); + final List output = await runCapturingPrint(runner, [ + 'federation-safety-check', + ]); expect( output, @@ -539,10 +631,14 @@ index abc123..def456 100644 test('allows things that look like mass changes, with warning', () async { final Directory pluginGroupDir = packagesDir.childDirectory('foo'); final RepositoryPackage appFacing = createFakePlugin('foo', pluginGroupDir); - final RepositoryPackage implementation = - createFakePlugin('foo_bar', pluginGroupDir); - final RepositoryPackage platformInterface = - createFakePlugin('foo_platform_interface', pluginGroupDir); + final RepositoryPackage implementation = createFakePlugin( + 'foo_bar', + pluginGroupDir, + ); + final RepositoryPackage platformInterface = createFakePlugin( + 'foo_platform_interface', + pluginGroupDir, + ); final RepositoryPackage otherPlugin1 = createFakePlugin('bar', packagesDir); final RepositoryPackage otherPlugin2 = createFakePlugin('baz', packagesDir); @@ -559,45 +655,50 @@ index abc123..def456 100644 FakeProcessInfo(MockProcess(stdout: changedFileOutput)), ]; - final List output = - await runCapturingPrint(runner, ['federation-safety-check']); + final List output = await runCapturingPrint(runner, [ + 'federation-safety-check', + ]); expect( output, containsAllInOrder([ contains('Running for foo/foo...'), contains( - 'Ignoring potentially dangerous change, as this appears to be a mass change.'), + 'Ignoring potentially dangerous change, as this appears to be a mass change.', + ), contains('Running for foo_bar...'), contains( - 'Ignoring potentially dangerous change, as this appears to be a mass change.'), + 'Ignoring potentially dangerous change, as this appears to be a mass change.', + ), contains('Ran for 2 package(s) (2 with warnings)'), ]), ); }); - test('handles top-level files that match federated package heuristics', - () async { - final RepositoryPackage plugin = createFakePlugin('foo', packagesDir); - - final String changedFileOutput = [ - // This should be picked up as a change to 'foo', and not crash. - plugin.directory.childFile('foo_bar.baz'), - ].map((File file) => file.path).join('\n'); - gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: changedFileOutput)), - ]; - - final List output = - await runCapturingPrint(runner, ['federation-safety-check']); - - expect( - output, - containsAllInOrder([ - contains('Running for foo...'), - ]), - ); - }); + test( + 'handles top-level files that match federated package heuristics', + () async { + final RepositoryPackage plugin = createFakePlugin('foo', packagesDir); + + final String changedFileOutput = [ + // This should be picked up as a change to 'foo', and not crash. + plugin.directory.childFile('foo_bar.baz'), + ].map((File file) => file.path).join('\n'); + gitProcessRunner.mockProcessesForExecutable['git-diff'] = + [ + FakeProcessInfo(MockProcess(stdout: changedFileOutput)), + ]; + + final List output = await runCapturingPrint(runner, [ + 'federation-safety-check', + ]); + + expect( + output, + containsAllInOrder([contains('Running for foo...')]), + ); + }, + ); test('handles deletion of an entire plugin', () async { // Simulate deletion, in the form of diffs for packages that don't exist in @@ -625,14 +726,13 @@ index abc123..def456 100644 FakeProcessInfo(MockProcess(stdout: changedFileOutput)), ]; - final List output = - await runCapturingPrint(runner, ['federation-safety-check']); + final List output = await runCapturingPrint(runner, [ + 'federation-safety-check', + ]); expect( output, - containsAllInOrder([ - contains('Ran for 0 package(s)'), - ]), + containsAllInOrder([contains('Ran for 0 package(s)')]), ); }); } diff --git a/script/tool/test/fetch_deps_command_test.dart b/script/tool/test/fetch_deps_command_test.dart index 92ad540ffe01..57c3a8c277a1 100644 --- a/script/tool/test/fetch_deps_command_test.dart +++ b/script/tool/test/fetch_deps_command_test.dart @@ -26,276 +26,312 @@ void main() { (:packagesDir, :processRunner, gitProcessRunner: _, :gitDir) = configureBaseCommandMocks(platform: mockPlatform); - final FetchDepsCommand command = FetchDepsCommand( + final command = FetchDepsCommand( packagesDir, processRunner: processRunner, platform: mockPlatform, gitDir: gitDir, ); - runner = - CommandRunner('fetch_deps_test', 'Test for $FetchDepsCommand'); + runner = CommandRunner( + 'fetch_deps_test', + 'Test for $FetchDepsCommand', + ); runner.addCommand(command); }); group('dart', () { test('runs pub get', () async { final RepositoryPackage plugin = createFakePlugin( - 'plugin1', packagesDir, platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline) - }); + 'plugin1', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); - final List output = - await runCapturingPrint(runner, ['fetch-deps']); + final List output = await runCapturingPrint(runner, [ + 'fetch-deps', + ]); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - 'flutter', - const ['pub', 'get'], - plugin.directory.path, - ), + ProcessCall('flutter', const [ + 'pub', + 'get', + ], plugin.directory.path), ]), ); expect( - output, - containsAllInOrder([ - contains('Running for plugin1'), - contains('No issues found!'), - ])); + output, + containsAllInOrder([ + contains('Running for plugin1'), + contains('No issues found!'), + ]), + ); }); test('runs pub get in non-example sub-packages', () async { final RepositoryPackage plugin = createFakePlugin( - 'plugin1', packagesDir, platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline) - }); + 'plugin1', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final RepositoryPackage subpackage = createFakePackage( - 'subpackage', plugin.directory.childDirectory('extras')); + 'subpackage', + plugin.directory.childDirectory('extras'), + ); - final List output = - await runCapturingPrint(runner, ['fetch-deps']); + final List output = await runCapturingPrint(runner, [ + 'fetch-deps', + ]); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - 'flutter', - const ['pub', 'get'], - plugin.directory.path, - ), - ProcessCall( - 'dart', - const ['pub', 'get'], - subpackage.directory.path, - ), + ProcessCall('flutter', const [ + 'pub', + 'get', + ], plugin.directory.path), + ProcessCall('dart', const [ + 'pub', + 'get', + ], subpackage.directory.path), ]), ); expect( - output, - containsAllInOrder([ - contains('Running for plugin1'), - contains('No issues found!'), - ])); + output, + containsAllInOrder([ + contains('Running for plugin1'), + contains('No issues found!'), + ]), + ); }); test('fails if pub get fails', () async { - createFakePlugin('plugin1', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline) - }); - - processRunner - .mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = - [ + createFakePlugin( + 'plugin1', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); + + processRunner.mockProcessesForExecutable[getFlutterCommand( + mockPlatform, + )] = [ FakeProcessInfo(MockProcess(exitCode: 1)), ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['fetch-deps'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['fetch-deps'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder( - [ - contains('Failed to "pub get"'), - ], - )); - }); - - test('skips unsupported packages when any platforms are passed', - () async { - final RepositoryPackage packageWithBoth = createFakePackage( - 'supports_both', packagesDir, extraFiles: [ - 'example/linux/placeholder', - 'example/windows/placeholder' - ]); - final RepositoryPackage packageWithOne = createFakePackage( - 'supports_one', packagesDir, - extraFiles: ['example/linux/placeholder']); - createFakePackage('supports_neither', packagesDir); - - await runCapturingPrint(runner, [ - 'fetch-deps', - '--linux', - '--windows', - '--supporting-target-platforms-only' - ]); - - expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'dart', - const ['pub', 'get'], - packageWithBoth.path, - ), - ProcessCall( - 'dart', - const ['pub', 'get'], - packageWithOne.path, - ), - ]), + output, + containsAllInOrder([contains('Failed to "pub get"')]), ); }); + + test( + 'skips unsupported packages when any platforms are passed', + () async { + final RepositoryPackage packageWithBoth = createFakePackage( + 'supports_both', + packagesDir, + extraFiles: [ + 'example/linux/placeholder', + 'example/windows/placeholder', + ], + ); + final RepositoryPackage packageWithOne = createFakePackage( + 'supports_one', + packagesDir, + extraFiles: ['example/linux/placeholder'], + ); + createFakePackage('supports_neither', packagesDir); + + await runCapturingPrint(runner, [ + 'fetch-deps', + '--linux', + '--windows', + '--supporting-target-platforms-only', + ]); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('dart', const [ + 'pub', + 'get', + ], packageWithBoth.path), + ProcessCall('dart', const [ + 'pub', + 'get', + ], packageWithOne.path), + ]), + ); + }, + ); }); group('android', () { test('runs pub get before gradlew dependencies', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin1', packagesDir, extraFiles: [ - 'example/android/gradlew', - ], platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin1', + packagesDir, + extraFiles: ['example/android/gradlew'], + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory androidDir = plugin .getExamples() .first .platformDirectory(FlutterPlatform.android); - final List output = await runCapturingPrint( - runner, ['fetch-deps', '--android']); + final List output = await runCapturingPrint(runner, [ + 'fetch-deps', + '--android', + ]); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - 'flutter', - const ['pub', 'get'], - plugin.directory.path, - ), - ProcessCall( - androidDir.childFile('gradlew').path, - const ['plugin1:dependencies'], - androidDir.path, - ), + ProcessCall('flutter', const [ + 'pub', + 'get', + ], plugin.directory.path), + ProcessCall(androidDir.childFile('gradlew').path, const [ + 'plugin1:dependencies', + ], androidDir.path), ]), ); expect( - output, - containsAllInOrder([ - contains('Running for plugin1'), - contains('No issues found!'), - ])); + output, + containsAllInOrder([ + contains('Running for plugin1'), + contains('No issues found!'), + ]), + ); }); test('runs gradlew dependencies', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin1', packagesDir, extraFiles: [ - 'example/android/gradlew', - ], platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin1', + packagesDir, + extraFiles: ['example/android/gradlew'], + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory androidDir = plugin .getExamples() .first .platformDirectory(FlutterPlatform.android); - final List output = await runCapturingPrint( - runner, ['fetch-deps', '--no-dart', '--android']); + final List output = await runCapturingPrint(runner, [ + 'fetch-deps', + '--no-dart', + '--android', + ]); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - androidDir.childFile('gradlew').path, - const ['plugin1:dependencies'], - androidDir.path, - ), + ProcessCall(androidDir.childFile('gradlew').path, const [ + 'plugin1:dependencies', + ], androidDir.path), ]), ); expect( - output, - containsAllInOrder([ - contains('Running for plugin1'), - contains('No issues found!'), - ])); + output, + containsAllInOrder([ + contains('Running for plugin1'), + contains('No issues found!'), + ]), + ); }); test('runs on all examples', () async { - final List examples = ['example1', 'example2']; + final examples = ['example1', 'example2']; final RepositoryPackage plugin = createFakePlugin( - 'plugin1', packagesDir, - examples: examples, - extraFiles: [ - 'example/example1/android/gradlew', - 'example/example2/android/gradlew', - ], - platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) - }); + 'plugin1', + packagesDir, + examples: examples, + extraFiles: [ + 'example/example1/android/gradlew', + 'example/example2/android/gradlew', + ], + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + }, + ); final Iterable exampleAndroidDirs = plugin.getExamples().map( - (RepositoryPackage example) => - example.platformDirectory(FlutterPlatform.android)); + (RepositoryPackage example) => + example.platformDirectory(FlutterPlatform.android), + ); - final List output = await runCapturingPrint( - runner, ['fetch-deps', '--no-dart', '--android']); + final List output = await runCapturingPrint(runner, [ + 'fetch-deps', + '--no-dart', + '--android', + ]); expect( processRunner.recordedCalls, orderedEquals([ for (final Directory directory in exampleAndroidDirs) - ProcessCall( - directory.childFile('gradlew').path, - const ['plugin1:dependencies'], - directory.path, - ), + ProcessCall(directory.childFile('gradlew').path, const [ + 'plugin1:dependencies', + ], directory.path), ]), ); expect( - output, - containsAllInOrder([ - contains('Running for plugin1'), - contains('No issues found!'), - ])); + output, + containsAllInOrder([ + contains('Running for plugin1'), + contains('No issues found!'), + ]), + ); }); test('runs --config-only build if gradlew is missing', () async { final RepositoryPackage plugin = createFakePlugin( - 'plugin1', packagesDir, platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) - }); + 'plugin1', + packagesDir, + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory androidDir = plugin .getExamples() .first .platformDirectory(FlutterPlatform.android); - final List output = await runCapturingPrint( - runner, ['fetch-deps', '--no-dart', '--android']); + final List output = await runCapturingPrint(runner, [ + 'fetch-deps', + '--no-dart', + '--android', + ]); expect( processRunner.recordedCalls, @@ -305,58 +341,63 @@ void main() { const ['build', 'apk', '--config-only'], plugin.getExamples().first.directory.path, ), - ProcessCall( - androidDir.childFile('gradlew').path, - const ['plugin1:dependencies'], - androidDir.path, - ), + ProcessCall(androidDir.childFile('gradlew').path, const [ + 'plugin1:dependencies', + ], androidDir.path), ]), ); expect( - output, - containsAllInOrder([ - contains('Running for plugin1'), - contains('No issues found!'), - ])); + output, + containsAllInOrder([ + contains('Running for plugin1'), + contains('No issues found!'), + ]), + ); }); test('fails if gradlew generation fails', () async { - createFakePlugin('plugin1', packagesDir, - platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) - }); - - processRunner - .mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = - [ + createFakePlugin( + 'plugin1', + packagesDir, + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + }, + ); + + processRunner.mockProcessesForExecutable[getFlutterCommand( + mockPlatform, + )] = [ FakeProcessInfo(MockProcess(exitCode: 1)), ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['fetch-deps', '--no-dart', '--android'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['fetch-deps', '--no-dart', '--android'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder( - [ - contains('Unable to configure Gradle project'), - ], - )); + output, + containsAllInOrder([ + contains('Unable to configure Gradle project'), + ]), + ); }); test('fails if dependency download finds issues', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin1', packagesDir, extraFiles: [ - 'example/android/gradlew', - ], platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin1', + packagesDir, + extraFiles: ['example/android/gradlew'], + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + }, + ); final String gradlewPath = plugin .getExamples() @@ -365,284 +406,314 @@ void main() { .childFile('gradlew') .path; processRunner.mockProcessesForExecutable[gradlewPath] = - [ - FakeProcessInfo(MockProcess(exitCode: 1)), - ]; + [FakeProcessInfo(MockProcess(exitCode: 1))]; Error? commandError; final List output = await runCapturingPrint( - runner, ['fetch-deps', '--no-dart', '--android'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['fetch-deps', '--no-dart', '--android'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder( - [ - contains('The following packages had errors:'), - ], - )); + output, + containsAllInOrder([ + contains('The following packages had errors:'), + ]), + ); }); test('skips non-Android plugins', () async { createFakePlugin('plugin1', packagesDir); - final List output = await runCapturingPrint( - runner, ['fetch-deps', '--no-dart', '--android']); + final List output = await runCapturingPrint(runner, [ + 'fetch-deps', + '--no-dart', + '--android', + ]); expect( - output, - containsAllInOrder( - [ - contains('Package does not have native Android dependencies.') - ], - )); + output, + containsAllInOrder([ + contains('Package does not have native Android dependencies.'), + ]), + ); }); test('skips non-inline plugins', () async { - createFakePlugin('plugin1', packagesDir, - platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.federated) - }); + createFakePlugin( + 'plugin1', + packagesDir, + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.federated), + }, + ); - final List output = await runCapturingPrint( - runner, ['fetch-deps', '--no-dart', '--android']); + final List output = await runCapturingPrint(runner, [ + 'fetch-deps', + '--no-dart', + '--android', + ]); expect( - output, - containsAllInOrder( - [ - contains('Package does not have native Android dependencies.') - ], - )); + output, + containsAllInOrder([ + contains('Package does not have native Android dependencies.'), + ]), + ); }); }); group('ios', () { test('runs on all examples', () async { - final List examples = ['example1', 'example2']; + final examples = ['example1', 'example2']; final RepositoryPackage plugin = createFakePlugin( - 'plugin1', packagesDir, - examples: examples, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline) - }); + 'plugin1', + packagesDir, + examples: examples, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); - final Iterable exampleDirs = plugin - .getExamples() - .map((RepositoryPackage example) => example.directory); + final Iterable exampleDirs = plugin.getExamples().map( + (RepositoryPackage example) => example.directory, + ); - final List output = await runCapturingPrint( - runner, ['fetch-deps', '--no-dart', '--ios']); + final List output = await runCapturingPrint(runner, [ + 'fetch-deps', + '--no-dart', + '--ios', + ]); expect( processRunner.recordedCalls, orderedEquals([ - const ProcessCall( - 'flutter', - ['precache', '--ios'], - null, - ), - const ProcessCall( - 'pod', - ['repo', 'update'], - null, - ), + const ProcessCall('flutter', ['precache', '--ios'], null), + const ProcessCall('pod', ['repo', 'update'], null), for (final Directory directory in exampleDirs) - ProcessCall( - 'flutter', - const ['build', 'ios', '--config-only'], - directory.path, - ), + ProcessCall('flutter', const [ + 'build', + 'ios', + '--config-only', + ], directory.path), ]), ); expect( - output, - containsAllInOrder([ - contains('Running for plugin1'), - contains('No issues found!'), - ])); + output, + containsAllInOrder([ + contains('Running for plugin1'), + contains('No issues found!'), + ]), + ); }); test('fails if flutter build --config-only fails', () async { - createFakePlugin('plugin1', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline) - }); - - processRunner - .mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = - [ + createFakePlugin( + 'plugin1', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); + + processRunner.mockProcessesForExecutable[getFlutterCommand( + mockPlatform, + )] = [ FakeProcessInfo(MockProcess(), ['precache']), FakeProcessInfo(MockProcess(), ['repo', 'update']), - FakeProcessInfo(MockProcess(exitCode: 1), - ['build', 'ios', '--config-only']), + FakeProcessInfo(MockProcess(exitCode: 1), [ + 'build', + 'ios', + '--config-only', + ]), ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['fetch-deps', '--no-dart', '--ios'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['fetch-deps', '--no-dart', '--ios'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder( - [ - contains('The following packages had errors:'), - ], - )); + output, + containsAllInOrder([ + contains('The following packages had errors:'), + ]), + ); }); test('skips non-iOS plugins', () async { createFakePlugin('plugin1', packagesDir); - final List output = await runCapturingPrint( - runner, ['fetch-deps', '--no-dart', '--ios']); + final List output = await runCapturingPrint(runner, [ + 'fetch-deps', + '--no-dart', + '--ios', + ]); expect( - output, - containsAllInOrder( - [ - contains('Package does not have native iOS dependencies.') - ], - )); + output, + containsAllInOrder([ + contains('Package does not have native iOS dependencies.'), + ]), + ); }); test('skips non-inline plugins', () async { - createFakePlugin('plugin1', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.federated) - }); + createFakePlugin( + 'plugin1', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.federated), + }, + ); - final List output = await runCapturingPrint( - runner, ['fetch-deps', '--no-dart', '--ios']); + final List output = await runCapturingPrint(runner, [ + 'fetch-deps', + '--no-dart', + '--ios', + ]); expect( - output, - containsAllInOrder( - [ - contains('Package does not have native iOS dependencies.') - ], - )); + output, + containsAllInOrder([ + contains('Package does not have native iOS dependencies.'), + ]), + ); }); }); group('macos', () { test('runs on all examples', () async { - final List examples = ['example1', 'example2']; + final examples = ['example1', 'example2']; final RepositoryPackage plugin = createFakePlugin( - 'plugin1', packagesDir, - examples: examples, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline) - }); + 'plugin1', + packagesDir, + examples: examples, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); - final Iterable exampleDirs = plugin - .getExamples() - .map((RepositoryPackage example) => example.directory); + final Iterable exampleDirs = plugin.getExamples().map( + (RepositoryPackage example) => example.directory, + ); - final List output = await runCapturingPrint( - runner, ['fetch-deps', '--no-dart', '--macos']); + final List output = await runCapturingPrint(runner, [ + 'fetch-deps', + '--no-dart', + '--macos', + ]); expect( processRunner.recordedCalls, orderedEquals([ - const ProcessCall( - 'flutter', - ['precache', '--macos'], - null, - ), - const ProcessCall( - 'pod', - ['repo', 'update'], - null, - ), + const ProcessCall('flutter', ['precache', '--macos'], null), + const ProcessCall('pod', ['repo', 'update'], null), for (final Directory directory in exampleDirs) - ProcessCall( - 'flutter', - const ['build', 'macos', '--config-only'], - directory.path, - ), + ProcessCall('flutter', const [ + 'build', + 'macos', + '--config-only', + ], directory.path), ]), ); expect( - output, - containsAllInOrder([ - contains('Running for plugin1'), - contains('No issues found!'), - ])); + output, + containsAllInOrder([ + contains('Running for plugin1'), + contains('No issues found!'), + ]), + ); }); test('fails if flutter build --config-only fails', () async { - createFakePlugin('plugin1', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline) - }); - - processRunner - .mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = - [ + createFakePlugin( + 'plugin1', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); + + processRunner.mockProcessesForExecutable[getFlutterCommand( + mockPlatform, + )] = [ FakeProcessInfo(MockProcess(), ['precache']), FakeProcessInfo(MockProcess(), ['repo', 'update']), - FakeProcessInfo(MockProcess(exitCode: 1), - ['build', 'macos', '--config-only']), + FakeProcessInfo(MockProcess(exitCode: 1), [ + 'build', + 'macos', + '--config-only', + ]), ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['fetch-deps', '--no-dart', '--macos'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['fetch-deps', '--no-dart', '--macos'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder( - [ - contains('The following packages had errors:'), - ], - )); + output, + containsAllInOrder([ + contains('The following packages had errors:'), + ]), + ); }); test('skips non-macOS plugins', () async { createFakePlugin('plugin1', packagesDir); - final List output = await runCapturingPrint( - runner, ['fetch-deps', '--no-dart', '--macos']); + final List output = await runCapturingPrint(runner, [ + 'fetch-deps', + '--no-dart', + '--macos', + ]); expect( - output, - containsAllInOrder( - [ - contains('Package does not have native macOS dependencies.') - ], - )); + output, + containsAllInOrder([ + contains('Package does not have native macOS dependencies.'), + ]), + ); }); test('skips non-inline plugins', () async { - createFakePlugin('plugin1', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.federated) - }); + createFakePlugin( + 'plugin1', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.federated), + }, + ); - final List output = await runCapturingPrint( - runner, ['fetch-deps', '--no-dart', '--macos']); + final List output = await runCapturingPrint(runner, [ + 'fetch-deps', + '--no-dart', + '--macos', + ]); expect( - output, - containsAllInOrder( - [ - contains('Package does not have native macOS dependencies.') - ], - )); + output, + containsAllInOrder([ + contains('Package does not have native macOS dependencies.'), + ]), + ); }); }); }); diff --git a/script/tool/test/firebase_test_lab_command_test.dart b/script/tool/test/firebase_test_lab_command_test.dart index 7141d7c0e436..e469e1f2c645 100644 --- a/script/tool/test/firebase_test_lab_command_test.dart +++ b/script/tool/test/firebase_test_lab_command_test.dart @@ -27,7 +27,7 @@ void main() { final GitDir gitDir; (:packagesDir, :processRunner, :gitProcessRunner, :gitDir) = configureBaseCommandMocks(platform: mockPlatform); - final FirebaseTestLabCommand command = FirebaseTestLabCommand( + final command = FirebaseTestLabCommand( packagesDir, processRunner: processRunner, platform: mockPlatform, @@ -35,15 +35,21 @@ void main() { ); runner = CommandRunner( - 'firebase_test_lab_command', 'Test for $FirebaseTestLabCommand'); + 'firebase_test_lab_command', + 'Test for $FirebaseTestLabCommand', + ); runner.addCommand(command); }); - void writeJavaTestFile(RepositoryPackage plugin, String relativeFilePath, - {String runnerClass = 'FlutterTestRunner'}) { + void writeJavaTestFile( + RepositoryPackage plugin, + String relativeFilePath, { + String runnerClass = 'FlutterTestRunner', + }) { childFileWithSubcomponents( - plugin.directory, p.posix.split(relativeFilePath)) - .writeAsStringSync(''' + plugin.directory, + p.posix.split(relativeFilePath), + ).writeAsStringSync(''' @DartIntegrationTest @RunWith($runnerClass.class) public class MainActivityTest { @@ -55,34 +61,42 @@ public class MainActivityTest { test('fails if gcloud auth fails', () async { processRunner.mockProcessesForExecutable['gcloud'] = [ - FakeProcessInfo(MockProcess(exitCode: 1), ['auth']) + FakeProcessInfo(MockProcess(exitCode: 1), ['auth']), ]; - const String javaTestFileRelativePath = + const javaTestFileRelativePath = 'example/android/app/src/androidTest/MainActivityTest.java'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/integration_test/foo_test.dart', - 'example/android/gradlew', - javaTestFileRelativePath, - ]); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'example/integration_test/foo_test.dart', + 'example/android/gradlew', + javaTestFileRelativePath, + ], + ); writeJavaTestFile(plugin, javaTestFileRelativePath); Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'firebase-test-lab', - '--results-bucket=a_bucket', - '--service-key=/path/to/key', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + [ + 'firebase-test-lab', + '--results-bucket=a_bucket', + '--service-key=/path/to/key', + ], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Unable to activate gcloud account.'), - ])); + output, + containsAllInOrder([ + contains('Unable to activate gcloud account.'), + ]), + ); }); test('retries gcloud set', () async { @@ -91,49 +105,60 @@ public class MainActivityTest { FakeProcessInfo(MockProcess(exitCode: 1), ['config']), ]; - const String javaTestFileRelativePath = + const javaTestFileRelativePath = 'example/android/app/src/androidTest/MainActivityTest.java'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/integration_test/foo_test.dart', - 'example/android/gradlew', - javaTestFileRelativePath, - ]); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'example/integration_test/foo_test.dart', + 'example/android/gradlew', + javaTestFileRelativePath, + ], + ); writeJavaTestFile(plugin, javaTestFileRelativePath); final List output = await runCapturingPrint(runner, [ 'firebase-test-lab', '--results-bucket=a_bucket', '--service-key=/path/to/key', - '--project=a-project' + '--project=a-project', ]); expect( - output, - containsAllInOrder([ - contains( - 'Warning: gcloud config set returned a non-zero exit code. Continuing anyway.'), - ])); + output, + containsAllInOrder([ + contains( + 'Warning: gcloud config set returned a non-zero exit code. Continuing anyway.', + ), + ]), + ); }); test('only runs gcloud configuration once', () async { - const String javaTestFileRelativePath = + const javaTestFileRelativePath = 'example/android/app/src/androidTest/MainActivityTest.java'; - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir, extraFiles: [ - 'test/plugin_test.dart', - 'example/integration_test/foo_test.dart', - 'example/android/gradlew', - javaTestFileRelativePath, - ]); + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + extraFiles: [ + 'test/plugin_test.dart', + 'example/integration_test/foo_test.dart', + 'example/android/gradlew', + javaTestFileRelativePath, + ], + ); writeJavaTestFile(plugin1, javaTestFileRelativePath); - final RepositoryPackage plugin2 = - createFakePlugin('plugin2', packagesDir, extraFiles: [ - 'test/plugin_test.dart', - 'example/integration_test/bar_test.dart', - 'example/android/gradlew', - javaTestFileRelativePath, - ]); + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir, + extraFiles: [ + 'test/plugin_test.dart', + 'example/integration_test/bar_test.dart', + 'example/android/gradlew', + javaTestFileRelativePath, + ], + ); writeJavaTestFile(plugin2, javaTestFileRelativePath); final List output = await runCapturingPrint(runner, [ @@ -165,65 +190,81 @@ public class MainActivityTest { expect( processRunner.recordedCalls, orderedEquals([ + ProcessCall('flutter', const [ + 'build', + 'apk', + '--debug', + '--config-only', + ], plugin1.getExamples().first.directory.path), ProcessCall( - 'flutter', - const ['build', 'apk', '--debug', '--config-only'], - plugin1.getExamples().first.directory.path), - ProcessCall( - 'gcloud', - 'auth activate-service-account --key-file=/path/to/key' - .split(' '), - null), - ProcessCall( - 'gcloud', 'config set project a-project'.split(' '), null), + 'gcloud', + 'auth activate-service-account --key-file=/path/to/key'.split(' '), + null, + ), ProcessCall( - '/packages/plugin1/example/android/gradlew', - 'app:assembleAndroidTest -Pverbose=true'.split(' '), - '/packages/plugin1/example/android'), + 'gcloud', + 'config set project a-project'.split(' '), + null, + ), ProcessCall( - '/packages/plugin1/example/android/gradlew', - 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin1/example/integration_test/foo_test.dart' - .split(' '), - '/packages/plugin1/example/android'), + '/packages/plugin1/example/android/gradlew', + 'app:assembleAndroidTest -Pverbose=true'.split(' '), + '/packages/plugin1/example/android', + ), ProcessCall( - 'gcloud', - 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 7m --results-bucket=gs://a_bucket --results-dir=plugins_android_test/plugin1/buildId/testRunId/example/0/ --device model=redfin,version=30 --device model=seoul,version=26' - .split(' '), - '/packages/plugin1/example'), + '/packages/plugin1/example/android/gradlew', + 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin1/example/integration_test/foo_test.dart' + .split(' '), + '/packages/plugin1/example/android', + ), ProcessCall( - 'flutter', - const ['build', 'apk', '--debug', '--config-only'], - plugin2.getExamples().first.directory.path), + 'gcloud', + 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 7m --results-bucket=gs://a_bucket --results-dir=plugins_android_test/plugin1/buildId/testRunId/example/0/ --device model=redfin,version=30 --device model=seoul,version=26' + .split(' '), + '/packages/plugin1/example', + ), + ProcessCall('flutter', const [ + 'build', + 'apk', + '--debug', + '--config-only', + ], plugin2.getExamples().first.directory.path), ProcessCall( - '/packages/plugin2/example/android/gradlew', - 'app:assembleAndroidTest -Pverbose=true'.split(' '), - '/packages/plugin2/example/android'), + '/packages/plugin2/example/android/gradlew', + 'app:assembleAndroidTest -Pverbose=true'.split(' '), + '/packages/plugin2/example/android', + ), ProcessCall( - '/packages/plugin2/example/android/gradlew', - 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin2/example/integration_test/bar_test.dart' - .split(' '), - '/packages/plugin2/example/android'), + '/packages/plugin2/example/android/gradlew', + 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin2/example/integration_test/bar_test.dart' + .split(' '), + '/packages/plugin2/example/android', + ), ProcessCall( - 'gcloud', - 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 7m --results-bucket=gs://a_bucket --results-dir=plugins_android_test/plugin2/buildId/testRunId/example/0/ --device model=redfin,version=30 --device model=seoul,version=26' - .split(' '), - '/packages/plugin2/example'), + 'gcloud', + 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 7m --results-bucket=gs://a_bucket --results-dir=plugins_android_test/plugin2/buildId/testRunId/example/0/ --device model=redfin,version=30 --device model=seoul,version=26' + .split(' '), + '/packages/plugin2/example', + ), ]), ); }); test('runs integration tests', () async { - const String javaTestFileRelativePath = + const javaTestFileRelativePath = 'example/android/app/src/androidTest/MainActivityTest.java'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'test/plugin_test.dart', - 'example/integration_test/bar_test.dart', - 'example/integration_test/foo_test.dart', - 'example/integration_test/should_not_run.dart', - 'example/android/gradlew', - javaTestFileRelativePath, - ]); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'test/plugin_test.dart', + 'example/integration_test/bar_test.dart', + 'example/integration_test/foo_test.dart', + 'example/integration_test/should_not_run.dart', + 'example/android/gradlew', + javaTestFileRelativePath, + ], + ); writeJavaTestFile(plugin, javaTestFileRelativePath); final List output = await runCapturingPrint(runner, [ @@ -248,60 +289,74 @@ public class MainActivityTest { ]), ); expect(output, isNot(contains('test/plugin_test.dart'))); - expect(output, - isNot(contains('example/integration_test/should_not_run.dart'))); + expect( + output, + isNot(contains('example/integration_test/should_not_run.dart')), + ); expect( processRunner.recordedCalls, orderedEquals([ + ProcessCall('flutter', const [ + 'build', + 'apk', + '--debug', + '--config-only', + ], plugin.getExamples().first.directory.path), ProcessCall( - 'flutter', - const ['build', 'apk', '--debug', '--config-only'], - plugin.getExamples().first.directory.path), - ProcessCall( - '/packages/plugin/example/android/gradlew', - 'app:assembleAndroidTest -Pverbose=true'.split(' '), - '/packages/plugin/example/android'), + '/packages/plugin/example/android/gradlew', + 'app:assembleAndroidTest -Pverbose=true'.split(' '), + '/packages/plugin/example/android', + ), ProcessCall( - '/packages/plugin/example/android/gradlew', - 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin/example/integration_test/bar_test.dart' - .split(' '), - '/packages/plugin/example/android'), + '/packages/plugin/example/android/gradlew', + 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin/example/integration_test/bar_test.dart' + .split(' '), + '/packages/plugin/example/android', + ), ProcessCall( - 'gcloud', - 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 7m --results-bucket=gs://a_bucket --results-dir=plugins_android_test/plugin/buildId/testRunId/example/0/ --device model=redfin,version=30 --device model=seoul,version=26' - .split(' '), - '/packages/plugin/example'), + 'gcloud', + 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 7m --results-bucket=gs://a_bucket --results-dir=plugins_android_test/plugin/buildId/testRunId/example/0/ --device model=redfin,version=30 --device model=seoul,version=26' + .split(' '), + '/packages/plugin/example', + ), ProcessCall( - '/packages/plugin/example/android/gradlew', - 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin/example/integration_test/foo_test.dart' - .split(' '), - '/packages/plugin/example/android'), + '/packages/plugin/example/android/gradlew', + 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin/example/integration_test/foo_test.dart' + .split(' '), + '/packages/plugin/example/android', + ), ProcessCall( - 'gcloud', - 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 7m --results-bucket=gs://a_bucket --results-dir=plugins_android_test/plugin/buildId/testRunId/example/1/ --device model=redfin,version=30 --device model=seoul,version=26' - .split(' '), - '/packages/plugin/example'), + 'gcloud', + 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 7m --results-bucket=gs://a_bucket --results-dir=plugins_android_test/plugin/buildId/testRunId/example/1/ --device model=redfin,version=30 --device model=seoul,version=26' + .split(' '), + '/packages/plugin/example', + ), ]), ); }); test('runs for all examples', () async { - const List examples = ['example1', 'example2']; - const String javaTestFileExampleRelativePath = + const examples = ['example1', 'example2']; + const javaTestFileExampleRelativePath = 'android/app/src/androidTest/MainActivityTest.java'; - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - examples: examples, - extraFiles: [ - for (final String example in examples) ...[ - 'example/$example/integration_test/a_test.dart', - 'example/$example/android/gradlew', - 'example/$example/$javaTestFileExampleRelativePath', - ], - ]); - for (final String example in examples) { + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: examples, + extraFiles: [ + for (final String example in examples) ...[ + 'example/$example/integration_test/a_test.dart', + 'example/$example/android/gradlew', + 'example/$example/$javaTestFileExampleRelativePath', + ], + ], + ); + for (final example in examples) { writeJavaTestFile( - plugin, 'example/$example/$javaTestFileExampleRelativePath'); + plugin, + 'example/$example/$javaTestFileExampleRelativePath', + ); } final List output = await runCapturingPrint(runner, [ @@ -329,48 +384,61 @@ public class MainActivityTest { processRunner.recordedCalls, containsAll([ ProcessCall( - '/packages/plugin/example/example1/android/gradlew', - 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin/example/example1/integration_test/a_test.dart' - .split(' '), - '/packages/plugin/example/example1/android'), + '/packages/plugin/example/example1/android/gradlew', + 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin/example/example1/integration_test/a_test.dart' + .split(' '), + '/packages/plugin/example/example1/android', + ), ProcessCall( - 'gcloud', - 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 7m --results-bucket=gs://a_bucket --results-dir=plugins_android_test/plugin/buildId/testRunId/example1/0/ --device model=redfin,version=30 --device model=seoul,version=26' - .split(' '), - '/packages/plugin/example/example1'), + 'gcloud', + 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 7m --results-bucket=gs://a_bucket --results-dir=plugins_android_test/plugin/buildId/testRunId/example1/0/ --device model=redfin,version=30 --device model=seoul,version=26' + .split(' '), + '/packages/plugin/example/example1', + ), ProcessCall( - '/packages/plugin/example/example2/android/gradlew', - 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin/example/example2/integration_test/a_test.dart' - .split(' '), - '/packages/plugin/example/example2/android'), + '/packages/plugin/example/example2/android/gradlew', + 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin/example/example2/integration_test/a_test.dart' + .split(' '), + '/packages/plugin/example/example2/android', + ), ProcessCall( - 'gcloud', - 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 7m --results-bucket=gs://a_bucket --results-dir=plugins_android_test/plugin/buildId/testRunId/example2/0/ --device model=redfin,version=30 --device model=seoul,version=26' - .split(' '), - '/packages/plugin/example/example2'), + 'gcloud', + 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 7m --results-bucket=gs://a_bucket --results-dir=plugins_android_test/plugin/buildId/testRunId/example2/0/ --device model=redfin,version=30 --device model=seoul,version=26' + .split(' '), + '/packages/plugin/example/example2', + ), ]), ); }); test('fails if a test fails twice', () async { - const String javaTestFileRelativePath = + const javaTestFileRelativePath = 'example/android/app/src/androidTest/MainActivityTest.java'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/integration_test/bar_test.dart', - 'example/integration_test/foo_test.dart', - 'example/android/gradlew', - javaTestFileRelativePath, - ]); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'example/integration_test/bar_test.dart', + 'example/integration_test/foo_test.dart', + 'example/android/gradlew', + javaTestFileRelativePath, + ], + ); writeJavaTestFile(plugin, javaTestFileRelativePath); processRunner.mockProcessesForExecutable['gcloud'] = [ - FakeProcessInfo(MockProcess(exitCode: 1), - ['firebase', 'test']), // integration test #1 - FakeProcessInfo(MockProcess(exitCode: 1), - ['firebase', 'test']), // integration test #1 retry - FakeProcessInfo( - MockProcess(), ['firebase', 'test']), // integration test #2 + FakeProcessInfo(MockProcess(exitCode: 1), [ + 'firebase', + 'test', + ]), // integration test #1 + FakeProcessInfo(MockProcess(exitCode: 1), [ + 'firebase', + 'test', + ]), // integration test #1 retry + FakeProcessInfo(MockProcess(), [ + 'firebase', + 'test', + ]), // integration test #2 ]; Error? commandError; @@ -393,57 +461,74 @@ public class MainActivityTest { containsAllInOrder([ contains('Testing example/integration_test/bar_test.dart...'), contains('Testing example/integration_test/foo_test.dart...'), - contains('plugin:\n' - ' example/integration_test/bar_test.dart failed tests'), + contains( + 'plugin:\n' + ' example/integration_test/bar_test.dart failed tests', + ), ]), ); }); - test('passes with warning if a test fails once, then passes on retry', - () async { - const String javaTestFileRelativePath = - 'example/android/app/src/androidTest/MainActivityTest.java'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/integration_test/bar_test.dart', - 'example/integration_test/foo_test.dart', - 'example/android/gradlew', - javaTestFileRelativePath, - ]); - writeJavaTestFile(plugin, javaTestFileRelativePath); - - processRunner.mockProcessesForExecutable['gcloud'] = [ - FakeProcessInfo(MockProcess(exitCode: 1), - ['firebase', 'test']), // integration test #1 - FakeProcessInfo(MockProcess(), - ['firebase', 'test']), // integration test #1 retry - FakeProcessInfo( - MockProcess(), ['firebase', 'test']), // integration test #2 - ]; + test( + 'passes with warning if a test fails once, then passes on retry', + () async { + const javaTestFileRelativePath = + 'example/android/app/src/androidTest/MainActivityTest.java'; + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'example/integration_test/bar_test.dart', + 'example/integration_test/foo_test.dart', + 'example/android/gradlew', + javaTestFileRelativePath, + ], + ); + writeJavaTestFile(plugin, javaTestFileRelativePath); + + processRunner.mockProcessesForExecutable['gcloud'] = [ + FakeProcessInfo(MockProcess(exitCode: 1), [ + 'firebase', + 'test', + ]), // integration test #1 + FakeProcessInfo(MockProcess(), [ + 'firebase', + 'test', + ]), // integration test #1 retry + FakeProcessInfo(MockProcess(), [ + 'firebase', + 'test', + ]), // integration test #2 + ]; - final List output = await runCapturingPrint(runner, [ - 'firebase-test-lab', - '--results-bucket=a_bucket', - '--device', - 'model=redfin,version=30', - ]); + final List output = await runCapturingPrint(runner, [ + 'firebase-test-lab', + '--results-bucket=a_bucket', + '--device', + 'model=redfin,version=30', + ]); - expect( - output, - containsAllInOrder([ - contains('Testing example/integration_test/bar_test.dart...'), - contains('bar_test.dart failed on attempt 1. Retrying...'), - contains('Testing example/integration_test/foo_test.dart...'), - contains('Ran for 1 package(s) (1 with warnings)'), - ]), - ); - }); + expect( + output, + containsAllInOrder([ + contains('Testing example/integration_test/bar_test.dart...'), + contains('bar_test.dart failed on attempt 1. Retrying...'), + contains('Testing example/integration_test/foo_test.dart...'), + contains('Ran for 1 package(s) (1 with warnings)'), + ]), + ); + }, + ); test('fails for plugins with no androidTest directory', () async { - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/integration_test/foo_test.dart', - 'example/android/gradlew', - ]); + createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'example/integration_test/foo_test.dart', + 'example/android/gradlew', + ], + ); Error? commandError; final List output = await runCapturingPrint( @@ -466,45 +551,56 @@ public class MainActivityTest { contains('Running for plugin'), contains('No androidTest directory found.'), contains('The following packages had errors:'), - contains('plugin:\n' - ' No tests ran (use --exclude if this is intentional).'), + contains( + 'plugin:\n' + ' No tests ran (use --exclude if this is intentional).', + ), ]), ); }); - test('skips for non-plugin packages with no androidTest directory', - () async { - createFakePackage('a_package', packagesDir, extraFiles: [ - 'example/integration_test/foo_test.dart', - 'example/android/gradlew', - ]); + test( + 'skips for non-plugin packages with no androidTest directory', + () async { + createFakePackage( + 'a_package', + packagesDir, + extraFiles: [ + 'example/integration_test/foo_test.dart', + 'example/android/gradlew', + ], + ); - final List output = await runCapturingPrint(runner, [ - 'firebase-test-lab', - '--results-bucket=a_bucket', - '--device', - 'model=redfin,version=30', - ]); + final List output = await runCapturingPrint(runner, [ + 'firebase-test-lab', + '--results-bucket=a_bucket', + '--device', + 'model=redfin,version=30', + ]); - expect( - output, - containsAllInOrder([ - contains('Running for a_package'), - contains('No androidTest directory found.'), - contains('No examples support Android.'), - contains('Skipped 1 package'), - ]), - ); - }); + expect( + output, + containsAllInOrder([ + contains('Running for a_package'), + contains('No androidTest directory found.'), + contains('No examples support Android.'), + contains('Skipped 1 package'), + ]), + ); + }, + ); test('fails for packages with no integration test files', () async { - const String javaTestFileRelativePath = + const javaTestFileRelativePath = 'example/android/app/src/androidTest/MainActivityTest.java'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/android/gradlew', - javaTestFileRelativePath, - ]); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'example/android/gradlew', + javaTestFileRelativePath, + ], + ); writeJavaTestFile(plugin, javaTestFileRelativePath); Error? commandError; @@ -528,27 +624,35 @@ public class MainActivityTest { contains('Running for plugin'), contains('No integration tests were run'), contains('The following packages had errors:'), - contains('plugin:\n' - ' No tests ran (use --exclude if this is intentional).'), + contains( + 'plugin:\n' + ' No tests ran (use --exclude if this is intentional).', + ), ]), ); }); test('fails for packages with no integration_test runner', () async { - const String javaTestFileRelativePath = + const javaTestFileRelativePath = 'example/android/app/src/androidTest/MainActivityTest.java'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'test/plugin_test.dart', - 'example/integration_test/bar_test.dart', - 'example/integration_test/foo_test.dart', - 'example/integration_test/should_not_run.dart', - 'example/android/gradlew', - javaTestFileRelativePath, - ]); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'test/plugin_test.dart', + 'example/integration_test/bar_test.dart', + 'example/integration_test/foo_test.dart', + 'example/integration_test/should_not_run.dart', + 'example/android/gradlew', + javaTestFileRelativePath, + ], + ); // Use the wrong @RunWith annotation. - writeJavaTestFile(plugin, javaTestFileRelativePath, - runnerClass: 'AndroidJUnit4.class'); + writeJavaTestFile( + plugin, + javaTestFileRelativePath, + runnerClass: 'AndroidJUnit4.class', + ); Error? commandError; final List output = await runCapturingPrint( @@ -569,29 +673,37 @@ public class MainActivityTest { output, containsAllInOrder([ contains('Running for plugin'), - contains('No integration_test runner found. ' - 'See the integration_test package README for setup instructions.'), - contains('plugin:\n' - ' No integration_test runner.'), + contains( + 'No integration_test runner found. ' + 'See the integration_test package README for setup instructions.', + ), + contains( + 'plugin:\n' + ' No integration_test runner.', + ), ]), ); }); test('supports kotlin implementation of integration_test runner', () async { - const String kotlinTestFileRelativePath = + const kotlinTestFileRelativePath = 'example/android/app/src/androidTest/MainActivityTest.kt'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'test/plugin_test.dart', - 'example/integration_test/foo_test.dart', - 'example/android/gradlew', - kotlinTestFileRelativePath, - ]); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'test/plugin_test.dart', + 'example/integration_test/foo_test.dart', + 'example/android/gradlew', + kotlinTestFileRelativePath, + ], + ); // Kotlin equivalent of the test runner childFileWithSubcomponents( - plugin.directory, p.posix.split(kotlinTestFileRelativePath)) - .writeAsStringSync(''' + plugin.directory, + p.posix.split(kotlinTestFileRelativePath), + ).writeAsStringSync(''' @DartIntegrationTest @RunWith(FlutterTestRunner::class) class MainActivityTest { @@ -599,30 +711,29 @@ class MainActivityTest { } '''); - final List output = await runCapturingPrint( - runner, - [ - 'firebase-test-lab', - '--results-bucket=a_bucket', - '--device', - 'model=redfin,version=30', - ], - ); + final List output = await runCapturingPrint(runner, [ + 'firebase-test-lab', + '--results-bucket=a_bucket', + '--device', + 'model=redfin,version=30', + ]); expect( output, containsAllInOrder([ contains('Running for plugin'), contains('Testing example/integration_test/foo_test.dart...'), - contains('Ran for 1 package') + contains('Ran for 1 package'), ]), ); }); test('skips packages with no android directory', () async { - createFakePackage('package', packagesDir, extraFiles: [ - 'example/integration_test/foo_test.dart', - ]); + createFakePackage( + 'package', + packagesDir, + extraFiles: ['example/integration_test/foo_test.dart'], + ); final List output = await runCapturingPrint(runner, [ 'firebase-test-lab', @@ -638,23 +749,25 @@ class MainActivityTest { contains('No examples support Android'), ]), ); - expect(output, - isNot(contains('Testing example/integration_test/foo_test.dart...'))); - expect( - processRunner.recordedCalls, - orderedEquals([]), + output, + isNot(contains('Testing example/integration_test/foo_test.dart...')), ); + + expect(processRunner.recordedCalls, orderedEquals([])); }); test('builds if gradlew is missing', () async { - const String javaTestFileRelativePath = + const javaTestFileRelativePath = 'example/android/app/src/androidTest/MainActivityTest.java'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/integration_test/foo_test.dart', - javaTestFileRelativePath, - ]); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'example/integration_test/foo_test.dart', + javaTestFileRelativePath, + ], + ); writeJavaTestFile(plugin, javaTestFileRelativePath); final List output = await runCapturingPrint(runner, [ @@ -686,35 +799,41 @@ class MainActivityTest { plugin.getExamples().first.directory.path, ), ProcessCall( - '/packages/plugin/example/android/gradlew', - 'app:assembleAndroidTest -Pverbose=true'.split(' '), - '/packages/plugin/example/android'), + '/packages/plugin/example/android/gradlew', + 'app:assembleAndroidTest -Pverbose=true'.split(' '), + '/packages/plugin/example/android', + ), ProcessCall( - '/packages/plugin/example/android/gradlew', - 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin/example/integration_test/foo_test.dart' - .split(' '), - '/packages/plugin/example/android'), + '/packages/plugin/example/android/gradlew', + 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin/example/integration_test/foo_test.dart' + .split(' '), + '/packages/plugin/example/android', + ), ProcessCall( - 'gcloud', - 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 7m --results-bucket=gs://a_bucket --results-dir=plugins_android_test/plugin/buildId/testRunId/example/0/ --device model=redfin,version=30' - .split(' '), - '/packages/plugin/example'), + 'gcloud', + 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 7m --results-bucket=gs://a_bucket --results-dir=plugins_android_test/plugin/buildId/testRunId/example/0/ --device model=redfin,version=30' + .split(' '), + '/packages/plugin/example', + ), ]), ); }); test('fails if building to generate gradlew fails', () async { - const String javaTestFileRelativePath = + const javaTestFileRelativePath = 'example/android/app/src/androidTest/MainActivityTest.java'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/integration_test/foo_test.dart', - javaTestFileRelativePath, - ]); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'example/integration_test/foo_test.dart', + javaTestFileRelativePath, + ], + ); writeJavaTestFile(plugin, javaTestFileRelativePath); processRunner.mockProcessesForExecutable['flutter'] = [ - FakeProcessInfo(MockProcess(exitCode: 1), ['build']) + FakeProcessInfo(MockProcess(exitCode: 1), ['build']), ]; Error? commandError; @@ -733,20 +852,22 @@ class MainActivityTest { expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Unable to build example apk'), - ])); + output, + containsAllInOrder([contains('Unable to build example apk')]), + ); }); test('fails if assembleAndroidTest fails', () async { - const String javaTestFileRelativePath = + const javaTestFileRelativePath = 'example/android/app/src/androidTest/MainActivityTest.java'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/integration_test/foo_test.dart', - javaTestFileRelativePath, - ]); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'example/integration_test/foo_test.dart', + javaTestFileRelativePath, + ], + ); writeJavaTestFile(plugin, javaTestFileRelativePath); final String gradlewPath = plugin @@ -756,8 +877,9 @@ class MainActivityTest { .childFile('gradlew') .path; processRunner.mockProcessesForExecutable[gradlewPath] = [ - FakeProcessInfo( - MockProcess(exitCode: 1), ['app:assembleAndroidTest']), + FakeProcessInfo(MockProcess(exitCode: 1), [ + 'app:assembleAndroidTest', + ]), ]; Error? commandError; @@ -776,20 +898,24 @@ class MainActivityTest { expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Unable to assemble androidTest'), - ])); + output, + containsAllInOrder([ + contains('Unable to assemble androidTest'), + ]), + ); }); test('fails if assembleDebug fails', () async { - const String javaTestFileRelativePath = + const javaTestFileRelativePath = 'example/android/app/src/androidTest/MainActivityTest.java'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/integration_test/foo_test.dart', - javaTestFileRelativePath, - ]); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'example/integration_test/foo_test.dart', + javaTestFileRelativePath, + ], + ); writeJavaTestFile(plugin, javaTestFileRelativePath); final String gradlewPath = plugin @@ -800,7 +926,9 @@ class MainActivityTest { .path; processRunner.mockProcessesForExecutable[gradlewPath] = [ FakeProcessInfo(MockProcess(), ['app:assembleAndroidTest']), - FakeProcessInfo(MockProcess(exitCode: 1), ['app:assembleDebug']) + FakeProcessInfo(MockProcess(exitCode: 1), [ + 'app:assembleDebug', + ]), ]; Error? commandError; @@ -819,24 +947,30 @@ class MainActivityTest { expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Could not build example/integration_test/foo_test.dart'), - contains('The following packages had errors:'), - contains(' plugin:\n' - ' example/integration_test/foo_test.dart failed to build'), - ])); + output, + containsAllInOrder([ + contains('Could not build example/integration_test/foo_test.dart'), + contains('The following packages had errors:'), + contains( + ' plugin:\n' + ' example/integration_test/foo_test.dart failed to build', + ), + ]), + ); }); test('experimental flag', () async { - const String javaTestFileRelativePath = + const javaTestFileRelativePath = 'example/android/app/src/androidTest/MainActivityTest.java'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/integration_test/foo_test.dart', - 'example/android/gradlew', - javaTestFileRelativePath, - ]); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'example/integration_test/foo_test.dart', + 'example/android/gradlew', + javaTestFileRelativePath, + ], + ); writeJavaTestFile(plugin, javaTestFileRelativePath); await runCapturingPrint(runner, [ @@ -854,37 +988,37 @@ class MainActivityTest { expect( processRunner.recordedCalls, orderedEquals([ + ProcessCall('flutter', const [ + 'build', + 'apk', + '--debug', + '--config-only', + '--enable-experiment=exp1', + ], plugin.getExamples().first.directory.path), ProcessCall( - 'flutter', - const [ - 'build', - 'apk', - '--debug', - '--config-only', - '--enable-experiment=exp1' - ], - plugin.getExamples().first.directory.path), - ProcessCall( - '/packages/plugin/example/android/gradlew', - 'app:assembleAndroidTest -Pverbose=true -Pextra-front-end-options=--enable-experiment%3Dexp1 -Pextra-gen-snapshot-options=--enable-experiment%3Dexp1' - .split(' '), - '/packages/plugin/example/android'), + '/packages/plugin/example/android/gradlew', + 'app:assembleAndroidTest -Pverbose=true -Pextra-front-end-options=--enable-experiment%3Dexp1 -Pextra-gen-snapshot-options=--enable-experiment%3Dexp1' + .split(' '), + '/packages/plugin/example/android', + ), ProcessCall( - '/packages/plugin/example/android/gradlew', - 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin/example/integration_test/foo_test.dart -Pextra-front-end-options=--enable-experiment%3Dexp1 -Pextra-gen-snapshot-options=--enable-experiment%3Dexp1' - .split(' '), - '/packages/plugin/example/android'), + '/packages/plugin/example/android/gradlew', + 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin/example/integration_test/foo_test.dart -Pextra-front-end-options=--enable-experiment%3Dexp1 -Pextra-gen-snapshot-options=--enable-experiment%3Dexp1' + .split(' '), + '/packages/plugin/example/android', + ), ProcessCall( - 'gcloud', - 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 7m --results-bucket=gs://a_bucket --results-dir=plugins_android_test/plugin/buildId/testRunId/example/0/ --device model=redfin,version=30' - .split(' '), - '/packages/plugin/example'), + 'gcloud', + 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 7m --results-bucket=gs://a_bucket --results-dir=plugins_android_test/plugin/buildId/testRunId/example/0/ --device model=redfin,version=30' + .split(' '), + '/packages/plugin/example', + ), ]), ); }); group('file filtering', () { - const List files = [ + const files = [ 'pubspec.yaml', 'foo.dart', 'foo.java', @@ -895,16 +1029,21 @@ class MainActivityTest { 'foo.cpp', 'foo.h', ]; - for (final String file in files) { + for (final file in files) { test('runs command for changes to $file', () async { createFakePackage('package_a', packagesDir); gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: + ''' packages/package_a/$file -''')), - ]; +''', + ), + ), + ]; final List output = await runCapturingPrint(runner, [ 'firebase-test-lab', @@ -914,10 +1053,9 @@ packages/package_a/$file ]); expect( - output, - containsAllInOrder([ - contains('Running for package_a'), - ])); + output, + containsAllInOrder([contains('Running for package_a')]), + ); }); } @@ -926,12 +1064,16 @@ packages/package_a/$file gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' README.md CODEOWNERS packages/package_a/CHANGELOG.md -''')), - ]; +''', + ), + ), + ]; final List output = await runCapturingPrint(runner, [ 'firebase-test-lab', @@ -941,15 +1083,15 @@ packages/package_a/CHANGELOG.md ]); expect( - output, - isNot(containsAllInOrder([ - contains('Running for package_a'), - ]))); + output, + isNot( + containsAllInOrder([contains('Running for package_a')]), + ), + ); expect( - output, - containsAllInOrder([ - contains('SKIPPING ALL PACKAGES'), - ])); + output, + containsAllInOrder([contains('SKIPPING ALL PACKAGES')]), + ); }); }); }); diff --git a/script/tool/test/fix_command_test.dart b/script/tool/test/fix_command_test.dart index 01eb5f471c49..306ddb861ac3 100644 --- a/script/tool/test/fix_command_test.dart +++ b/script/tool/test/fix_command_test.dart @@ -23,7 +23,7 @@ void main() { final GitDir gitDir; (:packagesDir, :processRunner, gitProcessRunner: _, :gitDir) = configureBaseCommandMocks(platform: mockPlatform); - final FixCommand command = FixCommand( + final command = FixCommand( packagesDir, processRunner: processRunner, platform: mockPlatform, @@ -41,15 +41,20 @@ void main() { await runCapturingPrint(runner, ['fix']); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall('dart', const ['fix', '--apply'], package.path), - ProcessCall('dart', const ['fix', '--apply'], - package.getExamples().first.path), - ProcessCall('dart', const ['fix', '--apply'], plugin.path), - ProcessCall('dart', const ['fix', '--apply'], - plugin.getExamples().first.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('dart', const ['fix', '--apply'], package.path), + ProcessCall('dart', const [ + 'fix', + '--apply', + ], package.getExamples().first.path), + ProcessCall('dart', const ['fix', '--apply'], plugin.path), + ProcessCall('dart', const [ + 'fix', + '--apply', + ], plugin.getExamples().first.path), + ]), + ); }); test('fails if "dart fix" fails', () async { @@ -60,10 +65,13 @@ void main() { ]; Error? commandError; - final List output = await runCapturingPrint(runner, ['fix'], - errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['fix'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( diff --git a/script/tool/test/format_command_test.dart b/script/tool/test/format_command_test.dart index 4a42efefd8c8..c74140997e5b 100644 --- a/script/tool/test/format_command_test.dart +++ b/script/tool/test/format_command_test.dart @@ -41,12 +41,15 @@ void main() { // Create the Java and Kotlin formatter files that the command checks for, // to avoid a download. final p.Context path = analyzeCommand.path; - javaFormatPath = path.join(path.dirname(path.fromUri(mockPlatform.script)), - 'google-java-format-1.3-all-deps.jar'); + javaFormatPath = path.join( + path.dirname(path.fromUri(mockPlatform.script)), + 'google-java-format-1.3-all-deps.jar', + ); packagesDir.fileSystem.file(javaFormatPath).createSync(recursive: true); kotlinFormatPath = path.join( - path.dirname(path.fromUri(mockPlatform.script)), - 'ktfmt-0.46-jar-with-dependencies.jar'); + path.dirname(path.fromUri(mockPlatform.script)), + 'ktfmt-0.46-jar-with-dependencies.jar', + ); packagesDir.fileSystem.file(kotlinFormatPath).createSync(recursive: true); runner = CommandRunner('format_command', 'Test for format_command'); @@ -55,8 +58,10 @@ void main() { /// Creates the .dart_tool directory for [package] to simulate (as much as /// this command requires) `pub get` having been run. - void fakePubGet(RepositoryPackage package, - {String languageVersion = _languageVersion}) { + void fakePubGet( + RepositoryPackage package, { + String languageVersion = _languageVersion, + }) { final File configFile = package.directory .childDirectory('.dart_tool') .childFile('package_config.json'); @@ -80,10 +85,14 @@ void main() { /// Returns a modified version of a list of [relativePaths] that are relative /// to [package] to instead be relative to [packagesDir]. List getPackagesDirRelativePaths( - RepositoryPackage package, List relativePaths) { + RepositoryPackage package, + List relativePaths, + ) { final p.Context path = analyzeCommand.path; - final String relativeBase = - path.relative(package.path, from: packagesDir.path); + final String relativeBase = path.relative( + package.path, + from: packagesDir.path, + ); return relativePaths .map((String relativePath) => path.join(relativeBase, relativePath)) .toList(); @@ -96,10 +105,11 @@ void main() { /// This is for each of testing batching, since it means each file will /// consume 100 characters of the batch length. List get99CharacterPathExtraFiles(int count) { - const int padding = 99 - + const int padding = + 99 - 1 - // the path separator after the padding 10; // the file name - const int filenameBase = 10000; + const filenameBase = 10000; final p.Context path = analyzeCommand.path; return [ @@ -110,11 +120,7 @@ void main() { group('dart format', () { test('formats .dart files', () async { - const List files = [ - 'lib/a.dart', - 'lib/src/b.dart', - 'lib/src/c.dart', - ]; + const files = ['lib/a.dart', 'lib/src/b.dart', 'lib/src/c.dart']; final RepositoryPackage plugin = createFakePlugin( 'a_plugin', packagesDir, @@ -126,77 +132,88 @@ void main() { await runCapturingPrint(runner, ['format']); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'dart', const ['format', ...files], plugin.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('dart', const ['format', ...files], plugin.path), + ]), + ); }); test('does not format .dart files with pragma', () async { - const List formattedFiles = [ + const formattedFiles = [ 'lib/a.dart', 'lib/src/b.dart', 'lib/src/c.dart', ]; - const String unformattedFile = 'lib/src/d.dart'; - final RepositoryPackage plugin = createFakePlugin('a_plugin', packagesDir, - extraFiles: [ - ...formattedFiles, - unformattedFile, - ], - dartConstraint: _dartConstraint); + const unformattedFile = 'lib/src/d.dart'; + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + extraFiles: [...formattedFiles, unformattedFile], + dartConstraint: _dartConstraint, + ); fakePubGet(plugin); final p.Context posixContext = p.posix; childFileWithSubcomponents( - plugin.directory, posixContext.split(unformattedFile)) - .writeAsStringSync( - '// copyright bla bla\n// This file is hand-formatted.\ncode...'); + plugin.directory, + posixContext.split(unformattedFile), + ).writeAsStringSync( + '// copyright bla bla\n// This file is hand-formatted.\ncode...', + ); await runCapturingPrint(runner, ['format']); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall('dart', const ['format', ...formattedFiles], - plugin.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('dart', const [ + 'format', + ...formattedFiles, + ], plugin.path), + ]), + ); }); test('fails if dart format fails', () async { - const List files = [ - 'lib/a.dart', - 'lib/src/b.dart', - 'lib/src/c.dart', - ]; - final RepositoryPackage plugin = createFakePlugin('a_plugin', packagesDir, - extraFiles: files, dartConstraint: _dartConstraint); + const files = ['lib/a.dart', 'lib/src/b.dart', 'lib/src/c.dart']; + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + extraFiles: files, + dartConstraint: _dartConstraint, + ); fakePubGet(plugin); processRunner.mockProcessesForExecutable['dart'] = [ - FakeProcessInfo(MockProcess(exitCode: 1), ['format']) + FakeProcessInfo(MockProcess(exitCode: 1), ['format']), ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['format'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['format'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Failed to format Dart files: exit code 1.'), - ])); + output, + containsAllInOrder([ + contains('Failed to format Dart files: exit code 1.'), + ]), + ); }); test('skips dart if --no-dart flag is provided', () async { - const List files = [ - 'lib/a.dart', - ]; - final RepositoryPackage plugin = createFakePlugin('a_plugin', packagesDir, - extraFiles: files, dartConstraint: _dartConstraint); + const files = ['lib/a.dart']; + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + extraFiles: files, + dartConstraint: _dartConstraint, + ); fakePubGet(plugin); await runCapturingPrint(runner, ['format', '--no-dart']); @@ -204,11 +221,7 @@ void main() { }); test('runs pub get if it has not been run', () async { - const List files = [ - 'lib/a.dart', - 'lib/src/b.dart', - 'lib/src/c.dart', - ]; + const files = ['lib/a.dart', 'lib/src/b.dart', 'lib/src/c.dart']; final RepositoryPackage plugin = createFakePlugin( 'a_plugin', packagesDir, @@ -219,24 +232,19 @@ void main() { await runCapturingPrint(runner, ['format']); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'flutter', - const ['pub', 'get'], - plugin.directory.path, - ), - ProcessCall( - 'dart', const ['format', ...files], plugin.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const [ + 'pub', + 'get', + ], plugin.directory.path), + ProcessCall('dart', const ['format', ...files], plugin.path), + ]), + ); }); test('runs pub get in subpackages if it has not been run', () async { - const List files = [ - 'lib/a.dart', - 'lib/src/b.dart', - 'lib/src/c.dart', - ]; + const files = ['lib/a.dart', 'lib/src/b.dart', 'lib/src/c.dart']; final RepositoryPackage plugin = createFakePlugin( 'a_plugin', packagesDir, @@ -244,34 +252,30 @@ void main() { dartConstraint: _dartConstraint, ); final RepositoryPackage subpackage = createFakePackage( - 'subpackage', plugin.directory.childDirectory('extras')); + 'subpackage', + plugin.directory.childDirectory('extras'), + ); await runCapturingPrint(runner, ['format']); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'flutter', - const ['pub', 'get'], - plugin.directory.path, - ), - ProcessCall( - 'dart', - const ['pub', 'get'], - subpackage.directory.path, - ), - ProcessCall( - 'dart', const ['format', ...files], plugin.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const [ + 'pub', + 'get', + ], plugin.directory.path), + ProcessCall('dart', const [ + 'pub', + 'get', + ], subpackage.directory.path), + ProcessCall('dart', const ['format', ...files], plugin.path), + ]), + ); }); test('runs pub get if the resolved language version is stale', () async { - const List files = [ - 'lib/a.dart', - 'lib/src/b.dart', - 'lib/src/c.dart', - ]; + const files = ['lib/a.dart', 'lib/src/b.dart', 'lib/src/c.dart']; final RepositoryPackage plugin = createFakePlugin( 'a_plugin', packagesDir, @@ -283,21 +287,20 @@ void main() { await runCapturingPrint(runner, ['format']); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'flutter', - const ['pub', 'get'], - plugin.directory.path, - ), - ProcessCall( - 'dart', const ['format', ...files], plugin.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const [ + 'pub', + 'get', + ], plugin.directory.path), + ProcessCall('dart', const ['format', ...files], plugin.path), + ]), + ); }); }); test('formats .java files', () async { - const List files = [ + const files = [ 'android/src/main/java/io/flutter/plugins/a_plugin/a.java', 'android/src/main/java/io/flutter/plugins/a_plugin/b.java', ]; @@ -311,79 +314,93 @@ void main() { await runCapturingPrint(runner, ['format']); expect( - processRunner.recordedCalls, - orderedEquals([ - const ProcessCall('java', ['-version'], null), - ProcessCall( - 'java', - [ - '-jar', - javaFormatPath, - '--replace', - ...getPackagesDirRelativePaths(plugin, files) - ], - packagesDir.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + const ProcessCall('java', ['-version'], null), + ProcessCall('java', [ + '-jar', + javaFormatPath, + '--replace', + ...getPackagesDirRelativePaths(plugin, files), + ], packagesDir.path), + ]), + ); }); test('fails with a clear message if Java is not in the path', () async { - const List files = [ + const files = [ 'android/src/main/java/io/flutter/plugins/a_plugin/a.java', 'android/src/main/java/io/flutter/plugins/a_plugin/b.java', ]; - final RepositoryPackage plugin = - createFakePlugin('a_plugin', packagesDir, extraFiles: files); + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + extraFiles: files, + ); fakePubGet(plugin); processRunner.mockProcessesForExecutable['java'] = [ - FakeProcessInfo(MockProcess(exitCode: 1), ['-version']) + FakeProcessInfo(MockProcess(exitCode: 1), ['-version']), ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['format'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['format'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains( - 'Unable to run "java". Make sure that it is in your path, or ' - 'provide a full path with --java-path.'), - ])); + output, + containsAllInOrder([ + contains( + 'Unable to run "java". Make sure that it is in your path, or ' + 'provide a full path with --java-path.', + ), + ]), + ); }); test('fails if Java formatter fails', () async { - const List files = [ + const files = [ 'android/src/main/java/io/flutter/plugins/a_plugin/a.java', 'android/src/main/java/io/flutter/plugins/a_plugin/b.java', ]; - final RepositoryPackage plugin = - createFakePlugin('a_plugin', packagesDir, extraFiles: files); + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + extraFiles: files, + ); fakePubGet(plugin); processRunner.mockProcessesForExecutable['java'] = [ - FakeProcessInfo( - MockProcess(), ['-version']), // check for working java + FakeProcessInfo(MockProcess(), [ + '-version', + ]), // check for working java FakeProcessInfo(MockProcess(exitCode: 1), ['-jar']), // format ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['format'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['format'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Failed to format Java files: exit code 1.'), - ])); + output, + containsAllInOrder([ + contains('Failed to format Java files: exit code 1.'), + ]), + ); }); test('honors --java-path flag', () async { - const List files = [ + const files = [ 'android/src/main/java/io/flutter/plugins/a_plugin/a.java', 'android/src/main/java/io/flutter/plugins/a_plugin/b.java', ]; @@ -394,31 +411,34 @@ void main() { ); fakePubGet(plugin); - await runCapturingPrint( - runner, ['format', '--java-path=/path/to/java']); + await runCapturingPrint(runner, [ + 'format', + '--java-path=/path/to/java', + ]); expect( - processRunner.recordedCalls, - orderedEquals([ - const ProcessCall('/path/to/java', ['--version'], null), - ProcessCall( - '/path/to/java', - [ - '-jar', - javaFormatPath, - '--replace', - ...getPackagesDirRelativePaths(plugin, files) - ], - packagesDir.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + const ProcessCall('/path/to/java', ['--version'], null), + ProcessCall('/path/to/java', [ + '-jar', + javaFormatPath, + '--replace', + ...getPackagesDirRelativePaths(plugin, files), + ], packagesDir.path), + ]), + ); }); test('skips Java if --no-java flag is provided', () async { - const List files = [ + const files = [ 'android/src/main/java/io/flutter/plugins/a_plugin/a.java', ]; - final RepositoryPackage plugin = - createFakePlugin('a_plugin', packagesDir, extraFiles: files); + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + extraFiles: files, + ); fakePubGet(plugin); await runCapturingPrint(runner, ['format', '--no-java']); @@ -426,7 +446,7 @@ void main() { }); test('formats c-ish files', () async { - const List files = [ + const files = [ 'ios/Classes/Foo.h', 'ios/Classes/Foo.m', 'linux/foo_plugin.cc', @@ -444,52 +464,55 @@ void main() { await runCapturingPrint(runner, ['format']); expect( - processRunner.recordedCalls, - orderedEquals([ - const ProcessCall('clang-format', ['--version'], null), - ProcessCall( - 'clang-format', - [ - '-i', - '--style=file', - ...getPackagesDirRelativePaths(plugin, files) - ], - packagesDir.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + const ProcessCall('clang-format', ['--version'], null), + ProcessCall('clang-format', [ + '-i', + '--style=file', + ...getPackagesDirRelativePaths(plugin, files), + ], packagesDir.path), + ]), + ); }); - test('fails with a clear message if clang-format is not in the path', - () async { - const List files = [ - 'linux/foo_plugin.cc', - 'macos/Classes/Foo.h', - ]; - final RepositoryPackage plugin = - createFakePlugin('a_plugin', packagesDir, extraFiles: files); - fakePubGet(plugin); + test( + 'fails with a clear message if clang-format is not in the path', + () async { + const files = ['linux/foo_plugin.cc', 'macos/Classes/Foo.h']; + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + extraFiles: files, + ); + fakePubGet(plugin); - processRunner.mockProcessesForExecutable['clang-format'] = - [FakeProcessInfo(MockProcess(exitCode: 1))]; - Error? commandError; - final List output = await runCapturingPrint( - runner, ['format'], errorHandler: (Error e) { - commandError = e; - }); + processRunner.mockProcessesForExecutable['clang-format'] = + [FakeProcessInfo(MockProcess(exitCode: 1))]; + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['format'], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( + expect(commandError, isA()); + expect( output, containsAllInOrder([ - contains('Unable to run "clang-format". Make sure that it is in your ' - 'path, or provide a full path with --clang-format-path.'), - ])); - }); + contains( + 'Unable to run "clang-format". Make sure that it is in your ' + 'path, or provide a full path with --clang-format-path.', + ), + ]), + ); + }, + ); test('falls back to working clang-format in the path', () async { - const List files = [ - 'linux/foo_plugin.cc', - 'macos/Classes/Foo.h', - ]; + const files = ['linux/foo_plugin.cc', 'macos/Classes/Foo.h']; final RepositoryPackage plugin = createFakePlugin( 'a_plugin', packagesDir, @@ -501,35 +524,33 @@ void main() { [FakeProcessInfo(MockProcess(exitCode: 1))]; processRunner.mockProcessesForExecutable['which'] = [ FakeProcessInfo( - MockProcess( - stdout: - '/usr/local/bin/clang-format\n/path/to/working-clang-format'), - ['-a', 'clang-format']) + MockProcess( + stdout: '/usr/local/bin/clang-format\n/path/to/working-clang-format', + ), + ['-a', 'clang-format'], + ), ]; processRunner.mockProcessesForExecutable['/usr/local/bin/clang-format'] = [FakeProcessInfo(MockProcess(exitCode: 1))]; await runCapturingPrint(runner, ['format']); expect( - processRunner.recordedCalls, - containsAll([ - const ProcessCall( - '/path/to/working-clang-format', ['--version'], null), - ProcessCall( - '/path/to/working-clang-format', - [ - '-i', - '--style=file', - ...getPackagesDirRelativePaths(plugin, files) - ], - packagesDir.path), - ])); + processRunner.recordedCalls, + containsAll([ + const ProcessCall('/path/to/working-clang-format', [ + '--version', + ], null), + ProcessCall('/path/to/working-clang-format', [ + '-i', + '--style=file', + ...getPackagesDirRelativePaths(plugin, files), + ], packagesDir.path), + ]), + ); }); test('honors --clang-format-path flag', () async { - const List files = [ - 'windows/foo_plugin.cpp', - ]; + const files = ['windows/foo_plugin.cpp']; final RepositoryPackage plugin = createFakePlugin( 'a_plugin', packagesDir, @@ -537,61 +558,67 @@ void main() { ); fakePubGet(plugin); - await runCapturingPrint(runner, - ['format', '--clang-format-path=/path/to/clang-format']); + await runCapturingPrint(runner, [ + 'format', + '--clang-format-path=/path/to/clang-format', + ]); expect( - processRunner.recordedCalls, - orderedEquals([ - const ProcessCall( - '/path/to/clang-format', ['--version'], null), - ProcessCall( - '/path/to/clang-format', - [ - '-i', - '--style=file', - ...getPackagesDirRelativePaths(plugin, files) - ], - packagesDir.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + const ProcessCall('/path/to/clang-format', ['--version'], null), + ProcessCall('/path/to/clang-format', [ + '-i', + '--style=file', + ...getPackagesDirRelativePaths(plugin, files), + ], packagesDir.path), + ]), + ); }); test('fails if clang-format fails', () async { - const List files = [ - 'linux/foo_plugin.cc', - 'macos/Classes/Foo.h', - ]; - final RepositoryPackage plugin = - createFakePlugin('a_plugin', packagesDir, extraFiles: files); + const files = ['linux/foo_plugin.cc', 'macos/Classes/Foo.h']; + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + extraFiles: files, + ); fakePubGet(plugin); processRunner.mockProcessesForExecutable['clang-format'] = [ - FakeProcessInfo(MockProcess(), - ['--version']), // check for working clang-format - FakeProcessInfo(MockProcess(exitCode: 1), ['-i']), // format - ]; + FakeProcessInfo(MockProcess(), [ + '--version', + ]), // check for working clang-format + FakeProcessInfo(MockProcess(exitCode: 1), ['-i']), // format + ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['format'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['format'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains( - 'Failed to format C, C++, and Objective-C files: exit code 1.'), - ])); + output, + containsAllInOrder([ + contains( + 'Failed to format C, C++, and Objective-C files: exit code 1.', + ), + ]), + ); }); test('skips clang-format if --no-clang-format flag is provided', () async { - const List files = [ - 'linux/foo_plugin.cc', - ]; - final RepositoryPackage plugin = - createFakePlugin('a_plugin', packagesDir, extraFiles: files); + const files = ['linux/foo_plugin.cc']; + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + extraFiles: files, + ); fakePubGet(plugin); await runCapturingPrint(runner, ['format', '--no-clang-format']); @@ -600,7 +627,7 @@ void main() { group('kotlin-format', () { test('formats .kt files', () async { - const List files = [ + const files = [ 'android/src/main/kotlin/io/flutter/plugins/a_plugin/a.kt', 'android/src/main/kotlin/io/flutter/plugins/a_plugin/b.kt', ]; @@ -614,54 +641,63 @@ void main() { await runCapturingPrint(runner, ['format']); expect( - processRunner.recordedCalls, - orderedEquals([ - const ProcessCall('java', ['-version'], null), - ProcessCall( - 'java', - [ - '-jar', - kotlinFormatPath, - ...getPackagesDirRelativePaths(plugin, files) - ], - packagesDir.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + const ProcessCall('java', ['-version'], null), + ProcessCall('java', [ + '-jar', + kotlinFormatPath, + ...getPackagesDirRelativePaths(plugin, files), + ], packagesDir.path), + ]), + ); }); test('fails if Kotlin formatter fails', () async { - const List files = [ + const files = [ 'android/src/main/kotlin/io/flutter/plugins/a_plugin/a.kt', 'android/src/main/kotlin/io/flutter/plugins/a_plugin/b.kt', ]; - final RepositoryPackage plugin = - createFakePlugin('a_plugin', packagesDir, extraFiles: files); + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + extraFiles: files, + ); fakePubGet(plugin); processRunner.mockProcessesForExecutable['java'] = [ - FakeProcessInfo( - MockProcess(), ['-version']), // check for working java + FakeProcessInfo(MockProcess(), [ + '-version', + ]), // check for working java FakeProcessInfo(MockProcess(exitCode: 1), ['-jar']), // format ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['format'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['format'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Failed to format Kotlin files: exit code 1.'), - ])); + output, + containsAllInOrder([ + contains('Failed to format Kotlin files: exit code 1.'), + ]), + ); }); test('skips Kotlin if --no-kotlin flag is provided', () async { - const List files = [ + const files = [ 'android/src/main/kotlin/io/flutter/plugins/a_plugin/a.kt', ]; - final RepositoryPackage plugin = - createFakePlugin('a_plugin', packagesDir, extraFiles: files); + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + extraFiles: files, + ); fakePubGet(plugin); await runCapturingPrint(runner, ['format', '--no-kotlin']); @@ -673,9 +709,7 @@ void main() { test('formats Swift if --swift flag is provided', () async { mockPlatform.isMacOS = false; - const List files = [ - 'macos/foo.swift', - ]; + const files = ['macos/foo.swift']; final RepositoryPackage plugin = createFakePlugin( 'a_plugin', packagesDir, @@ -683,43 +717,31 @@ void main() { ); fakePubGet(plugin); - await runCapturingPrint(runner, [ - 'format', - '--swift', - ]); + await runCapturingPrint(runner, ['format', '--swift']); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'xcrun', - [ - 'swift-format', - '-i', - ...getPackagesDirRelativePaths(plugin, files) - ], - packagesDir.path, - ), - ProcessCall( - 'xcrun', - [ - 'swift-format', - 'lint', - '--parallel', - '--strict', - ...getPackagesDirRelativePaths(plugin, files), - ], - packagesDir.path, - ), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('xcrun', [ + 'swift-format', + '-i', + ...getPackagesDirRelativePaths(plugin, files), + ], packagesDir.path), + ProcessCall('xcrun', [ + 'swift-format', + 'lint', + '--parallel', + '--strict', + ...getPackagesDirRelativePaths(plugin, files), + ], packagesDir.path), + ]), + ); }); test('skips Swift if --no-swift flag is provided', () async { mockPlatform.isMacOS = true; - const List files = [ - 'macos/foo.swift', - ]; + const files = ['macos/foo.swift']; final RepositoryPackage plugin = createFakePlugin( 'a_plugin', packagesDir, @@ -733,11 +755,12 @@ void main() { }); test('fails if swift-format lint finds issues', () async { - const List files = [ - 'macos/foo.swift', - ]; - final RepositoryPackage plugin = - createFakePlugin('a_plugin', packagesDir, extraFiles: files); + const files = ['macos/foo.swift']; + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + extraFiles: files, + ); fakePubGet(plugin); processRunner.mockProcessesForExecutable['xcrun'] = [ @@ -750,27 +773,30 @@ void main() { ]), ]; Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'format', - '--swift', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['format', '--swift'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Swift linter found issues. See above for linter output.'), - ])); + output, + containsAllInOrder([ + contains('Swift linter found issues. See above for linter output.'), + ]), + ); }); test('fails if swift-format lint fails', () async { - const List files = [ - 'macos/foo.swift', - ]; - final RepositoryPackage plugin = - createFakePlugin('a_plugin', packagesDir, extraFiles: files); + const files = ['macos/foo.swift']; + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + extraFiles: files, + ); fakePubGet(plugin); processRunner.mockProcessesForExecutable['xcrun'] = [ @@ -783,62 +809,69 @@ void main() { ]), ]; Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'format', - '--swift', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['format', '--swift'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Failed to lint Swift files: exit code 99.'), - ])); + output, + containsAllInOrder([ + contains('Failed to lint Swift files: exit code 99.'), + ]), + ); }); test('fails if swift-format fails', () async { - const List files = [ - 'macos/foo.swift', - ]; - final RepositoryPackage plugin = - createFakePlugin('a_plugin', packagesDir, extraFiles: files); + const files = ['macos/foo.swift']; + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + extraFiles: files, + ); fakePubGet(plugin); processRunner.mockProcessesForExecutable['xcrun'] = [ - FakeProcessInfo( - MockProcess(exitCode: 1), ['swift-format', '-i']), + FakeProcessInfo(MockProcess(exitCode: 1), [ + 'swift-format', + '-i', + ]), ]; Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'format', - '--swift', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['format', '--swift'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Failed to format Swift files: exit code 1.'), - ])); + output, + containsAllInOrder([ + contains('Failed to format Swift files: exit code 1.'), + ]), + ); }); }); test('skips known non-repo files', () async { - const List skipFiles = [ + const skipFiles = [ '/example/build/SomeFramework.framework/Headers/SomeFramework.h', '/example/Pods/APod.framework/Headers/APod.h', '.dart_tool/internals/foo.cc', '.dart_tool/internals/Bar.java', '.dart_tool/internals/baz.dart', ]; - const List clangFiles = ['ios/Classes/Foo.h']; - const List dartFiles = ['lib/a.dart']; - const List javaFiles = [ - 'android/src/main/java/io/flutter/plugins/a_plugin/a.java' + const clangFiles = ['ios/Classes/Foo.h']; + const dartFiles = ['lib/a.dart']; + const javaFiles = [ + 'android/src/main/java/io/flutter/plugins/a_plugin/a.java', ]; final RepositoryPackage plugin = createFakePlugin( 'a_plugin', @@ -857,32 +890,29 @@ void main() { await runCapturingPrint(runner, ['format']); expect( - processRunner.recordedCalls, - containsAll([ - ProcessCall( - 'clang-format', - [ - '-i', - '--style=file', - ...getPackagesDirRelativePaths(plugin, clangFiles) - ], - packagesDir.path), - ProcessCall( - 'dart', const ['format', ...dartFiles], plugin.path), - ProcessCall( - 'java', - [ - '-jar', - javaFormatPath, - '--replace', - ...getPackagesDirRelativePaths(plugin, javaFiles) - ], - packagesDir.path), - ])); + processRunner.recordedCalls, + containsAll([ + ProcessCall('clang-format', [ + '-i', + '--style=file', + ...getPackagesDirRelativePaths(plugin, clangFiles), + ], packagesDir.path), + ProcessCall('dart', const [ + 'format', + ...dartFiles, + ], plugin.path), + ProcessCall('java', [ + '-jar', + javaFormatPath, + '--replace', + ...getPackagesDirRelativePaths(plugin, javaFiles), + ], packagesDir.path), + ]), + ); }); test('skips GeneratedPluginRegistrant.swift', () async { - const String sourceFile = 'macos/Classes/Foo.swift'; + const sourceFile = 'macos/Classes/Foo.swift'; final RepositoryPackage plugin = createFakePlugin( 'a_plugin', packagesDir, @@ -893,155 +923,154 @@ void main() { ); fakePubGet(plugin); - await runCapturingPrint(runner, [ - 'format', - '--swift', - ]); + await runCapturingPrint(runner, ['format', '--swift']); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'xcrun', - [ - 'swift-format', - '-i', - ...getPackagesDirRelativePaths(plugin, [sourceFile]) - ], - packagesDir.path, - ), - ProcessCall( - 'xcrun', - [ - 'swift-format', - 'lint', - '--parallel', - '--strict', - ...getPackagesDirRelativePaths(plugin, [sourceFile]), - ], - packagesDir.path, - ), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('xcrun', [ + 'swift-format', + '-i', + ...getPackagesDirRelativePaths(plugin, [sourceFile]), + ], packagesDir.path), + ProcessCall('xcrun', [ + 'swift-format', + 'lint', + '--parallel', + '--strict', + ...getPackagesDirRelativePaths(plugin, [sourceFile]), + ], packagesDir.path), + ]), + ); }); test('fails if files are changed with --fail-on-change', () async { - const List files = [ - 'linux/foo_plugin.cc', - 'macos/Classes/Foo.h', - ]; - final RepositoryPackage plugin = - createFakePlugin('a_plugin', packagesDir, extraFiles: files); + const files = ['linux/foo_plugin.cc', 'macos/Classes/Foo.h']; + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + extraFiles: files, + ); fakePubGet(plugin); - const String changedFilePath = 'packages/a_plugin/linux/foo_plugin.cc'; + const changedFilePath = 'packages/a_plugin/linux/foo_plugin.cc'; processRunner.mockProcessesForExecutable['git'] = [ - FakeProcessInfo( - MockProcess(stdout: changedFilePath), ['ls-files']), + FakeProcessInfo(MockProcess(stdout: changedFilePath), [ + 'ls-files', + ]), ]; Error? commandError; - final List output = - await runCapturingPrint(runner, ['format', '--fail-on-change'], - errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['format', '--fail-on-change'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('These files are not formatted correctly'), - contains(changedFilePath), - // Ensure the error message links to instructions. - contains( - 'https://github.com/flutter/packages/blob/main/script/tool/README.md#format-code'), - contains('patch -p1 <[ + contains('These files are not formatted correctly'), + contains(changedFilePath), + // Ensure the error message links to instructions. + contains( + 'https://github.com/flutter/packages/blob/main/script/tool/README.md#format-code', + ), + contains('patch -p1 <[ - ProcessCall( - 'git', - [ - 'ls-files', - '--modified', - packagesDir.path, - thirdPartyDir.path - ], - packagesDir.parent.path, - ), - ])); + processRunner.recordedCalls, + containsAllInOrder([ + ProcessCall('git', [ + 'ls-files', + '--modified', + packagesDir.path, + thirdPartyDir.path, + ], packagesDir.parent.path), + ]), + ); }); test('fails if git ls-files fails', () async { - const List files = [ - 'linux/foo_plugin.cc', - 'macos/Classes/Foo.h', - ]; - final RepositoryPackage plugin = - createFakePlugin('a_plugin', packagesDir, extraFiles: files); + const files = ['linux/foo_plugin.cc', 'macos/Classes/Foo.h']; + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + extraFiles: files, + ); fakePubGet(plugin); processRunner.mockProcessesForExecutable['git'] = [ - FakeProcessInfo(MockProcess(exitCode: 1), ['ls-files']) + FakeProcessInfo(MockProcess(exitCode: 1), ['ls-files']), ]; Error? commandError; - final List output = - await runCapturingPrint(runner, ['format', '--fail-on-change'], - errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['format', '--fail-on-change'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Unable to determine changed files.'), - ])); + output, + containsAllInOrder([ + contains('Unable to determine changed files.'), + ]), + ); }); test('reports git diff failures', () async { - const List files = [ - 'linux/foo_plugin.cc', - 'macos/Classes/Foo.h', - ]; - final RepositoryPackage plugin = - createFakePlugin('a_plugin', packagesDir, extraFiles: files); + const files = ['linux/foo_plugin.cc', 'macos/Classes/Foo.h']; + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + extraFiles: files, + ); fakePubGet(plugin); - const String changedFilePath = 'packages/a_plugin/linux/foo_plugin.cc'; + const changedFilePath = 'packages/a_plugin/linux/foo_plugin.cc'; processRunner.mockProcessesForExecutable['git'] = [ - FakeProcessInfo( - MockProcess(stdout: changedFilePath), ['ls-files']), + FakeProcessInfo(MockProcess(stdout: changedFilePath), [ + 'ls-files', + ]), FakeProcessInfo(MockProcess(exitCode: 1), ['diff']), ]; Error? commandError; - final List output = - await runCapturingPrint(runner, ['format', '--fail-on-change'], - errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['format', '--fail-on-change'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('These files are not formatted correctly'), - contains(changedFilePath), - contains('Unable to determine diff.'), - ])); + output, + containsAllInOrder([ + contains('These files are not formatted correctly'), + contains(changedFilePath), + contains('Unable to determine diff.'), + ]), + ); }); test('Batches moderately long file lists on Windows', () async { mockPlatform.isWindows = true; - const String pluginName = 'a_plugin'; + const pluginName = 'a_plugin'; // -1 since the command itself takes some length. const int batchSize = (windowsCommandLineMax ~/ 100) - 1; @@ -1063,23 +1092,18 @@ void main() { expect(processRunner.recordedCalls.length, 2); // ... and that the spillover into the second batch was only one file. expect( - processRunner.recordedCalls, - contains( - ProcessCall( - 'dart', - [ - 'format', - extraFile, - ], - package.path), - )); + processRunner.recordedCalls, + contains( + ProcessCall('dart', ['format', extraFile], package.path), + ), + ); }); // Validates that the Windows limit--which is much lower than the limit on // other platforms--isn't being used on all platforms, as that would make // formatting slower on Linux and macOS. test('Does not batch moderately long file lists on non-Windows', () async { - const String pluginName = 'a_plugin'; + const pluginName = 'a_plugin'; // -1 since the command itself takes some length. const int batchSize = (windowsCommandLineMax ~/ 100) - 1; @@ -1100,7 +1124,7 @@ void main() { }); test('Batches extremely long file lists on non-Windows', () async { - const String pluginName = 'a_plugin'; + const pluginName = 'a_plugin'; // -1 since the command itself takes some length. const int batchSize = (nonWindowsCommandLineMax ~/ 100) - 1; @@ -1122,15 +1146,10 @@ void main() { expect(processRunner.recordedCalls.length, 2); // ... and that the spillover into the second batch was only one file. expect( - processRunner.recordedCalls, - contains( - ProcessCall( - 'dart', - [ - 'format', - extraFile, - ], - package.path), - )); + processRunner.recordedCalls, + contains( + ProcessCall('dart', ['format', extraFile], package.path), + ), + ); }); } diff --git a/script/tool/test/gradle_check_command_test.dart b/script/tool/test/gradle_check_command_test.dart index 3ca0fe0f0918..dfb386fe6d45 100644 --- a/script/tool/test/gradle_check_command_test.dart +++ b/script/tool/test/gradle_check_command_test.dart @@ -17,20 +17,19 @@ const String _defaultFakeNamespace = 'dev.flutter.foo'; void main() { late CommandRunner runner; late Directory packagesDir; - const String javaIncompatabilityIndicator = + const javaIncompatabilityIndicator = 'build.gradle(.kts) must set an explicit Java compatibility version.'; setUp(() { final GitDir gitDir; (:packagesDir, processRunner: _, gitProcessRunner: _, :gitDir) = configureBaseCommandMocks(); - final GradleCheckCommand command = GradleCheckCommand( - packagesDir, - gitDir: gitDir, - ); + final command = GradleCheckCommand(packagesDir, gitDir: gitDir); runner = CommandRunner( - 'gradle_check_command', 'Test for gradle_check_command'); + 'gradle_check_command', + 'Test for gradle_check_command', + ); runner.addCommand(command); }); @@ -59,7 +58,7 @@ void main() { .childFile('build.gradle'); buildGradle.createSync(recursive: true); - const String warningConfig = ''' + const warningConfig = ''' lintOptions { checkAllWarnings = true warningsAsErrors = true @@ -67,7 +66,8 @@ void main() { baseline file("lint-baseline.xml") } '''; - final String javaSection = ''' + final javaSection = + ''' java { toolchain { ${commentSourceLanguage ? '// ' : ''}languageVersion = JavaLanguageVersion.of(8) @@ -75,16 +75,17 @@ java { } '''; - final String sourceCompat = + final sourceCompat = '${commentSourceLanguage ? '// ' : ''}sourceCompatibility = JavaVersion.VERSION_$jvmTargetValue'; - final String targetCompat = + final targetCompat = '${commentSourceLanguage ? '// ' : ''}targetCompatibility = JavaVersion.VERSION_$jvmTargetValue'; - final String namespace = + final namespace = " ${commentNamespace ? '// ' : ''}namespace = '$_defaultFakeNamespace'"; - final String kotlinJvmTarget = useDeprecatedJvmTargetStyle + final kotlinJvmTarget = useDeprecatedJvmTargetStyle ? '$jvmTargetValue' : 'JavaVersion.VERSION_$kotlinJvmValue.toString()'; - final String kotlinConfig = ''' + final kotlinConfig = + ''' ${commentKotlinOptions ? '//' : ''}kotlinOptions { ${commentKotlinOptions ? '//' : ''}jvmTarget = $kotlinJvmTarget ${commentKotlinOptions ? '//' : ''}}'''; @@ -141,7 +142,8 @@ dependencies { .childFile('build.gradle'); buildGradle.createSync(recursive: true); - final String warningConfig = ''' + final warningConfig = + ''' gradle.projectsEvaluated { project(":$pluginName") { tasks.withType(JavaCompile) { @@ -201,7 +203,7 @@ ${warningsConfigured ? warningConfig : ''} /// String printed as a valid example of settings.gradle repository /// configuration without the artifact hub env variable. - const String exampleSettingsWithoutArtifactHubString = ''' + const exampleSettingsWithoutArtifactHubString = ''' plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" // ...other plugins @@ -248,7 +250,7 @@ include ":app" .childFile('build.gradle'); buildGradle.createSync(recursive: true); - final String namespace = + final namespace = "${commentNamespace ? '// ' : ''}namespace ${includeNameSpaceAsDeclaration ? '= ' : ''}'$_defaultFakeNamespace'"; buildGradle.writeAsStringSync(''' def flutterRoot = localProperties.getProperty('flutter.sdk') @@ -304,11 +306,13 @@ dependencies { kotlinVersion: kotlinVersion, includeArtifactHub: includeBuildArtifactHub, ); - writeFakeExampleAppBuildGradle(package, - includeNamespace: includeNamespace, - commentNamespace: commentNamespace, - includeNameSpaceAsDeclaration: includeNameSpaceAsDeclaration, - usePropertyAssignment: usePropertyAssignment); + writeFakeExampleAppBuildGradle( + package, + includeNamespace: includeNamespace, + commentNamespace: commentNamespace, + includeNameSpaceAsDeclaration: includeNameSpaceAsDeclaration, + usePropertyAssignment: usePropertyAssignment, + ); writeFakeExampleSettingsGradle( package, includeArtifactHub: includeSettingsArtifactHub, @@ -321,10 +325,12 @@ dependencies { bool isApp = false, String packageName = _defaultFakeNamespace, }) { - final Directory androidDir = - package.platformDirectory(FlutterPlatform.android); - final Directory startDir = - isApp ? androidDir.childDirectory('app') : androidDir; + final Directory androidDir = package.platformDirectory( + FlutterPlatform.android, + ); + final Directory startDir = isApp + ? androidDir.childDirectory('app') + : androidDir; final File manifest = startDir .childDirectory('src') .childDirectory('main') @@ -339,93 +345,113 @@ dependencies { test('skips when package has no Android directory', () async { createFakePackage('a_package', packagesDir, examples: []); - final List output = - await runCapturingPrint(runner, ['gradle-check']); + final List output = await runCapturingPrint(runner, [ + 'gradle-check', + ]); expect( output, - containsAllInOrder([ - contains('Skipped 1 package(s)'), - ]), + containsAllInOrder([contains('Skipped 1 package(s)')]), ); }); test('fails when build.gradle has no java compatibility version', () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir, examples: []); + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + examples: [], + ); writeFakePluginBuildGradle(package); writeFakeManifest(package); Error? commandError; final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, - containsAllInOrder([ - contains(javaIncompatabilityIndicator), - ]), + containsAllInOrder([contains(javaIncompatabilityIndicator)]), ); }); test( - 'fails when sourceCompatibility is provided with out targetCompatibility', - () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir, examples: []); - writeFakePluginBuildGradle(package, includeSourceCompat: true); - writeFakeManifest(package); + 'fails when sourceCompatibility is provided with out targetCompatibility', + () async { + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + examples: [], + ); + writeFakePluginBuildGradle(package, includeSourceCompat: true); + writeFakeManifest(package); - Error? commandError; - final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains(javaIncompatabilityIndicator), - ]), - ); - }); + expect(commandError, isA()); + expect( + output, + containsAllInOrder([contains(javaIncompatabilityIndicator)]), + ); + }, + ); - test('fails when sourceCompatibility/targetCompatibility are below minimum', - () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir, examples: []); - writeFakePluginBuildGradle( - package, - includeSourceCompat: true, - includeTargetCompat: true, - jvmTargetValue: 11, - kotlinJvmValue: 11, - ); - writeFakeManifest(package); + test( + 'fails when sourceCompatibility/targetCompatibility are below minimum', + () async { + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + examples: [], + ); + writeFakePluginBuildGradle( + package, + includeSourceCompat: true, + includeTargetCompat: true, + jvmTargetValue: 11, + kotlinJvmValue: 11, + ); + writeFakeManifest(package); - Error? commandError; - final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains( - 'Which is below the minimum required. Use at least "JavaVersion.VERSION_'), - ]), - ); - }); + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains( + 'Which is below the minimum required. Use at least "JavaVersion.VERSION_', + ), + ]), + ); + }, + ); test('fails when compatibility values do not match kotlinOptions', () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir, examples: []); + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + examples: [], + ); writeFakePluginBuildGradle( package, includeSourceCompat: true, @@ -438,23 +464,30 @@ dependencies { Error? commandError; final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - 'If build.gradle(.kts) uses JavaVersion.* versions must be the same.'), + 'If build.gradle(.kts) uses JavaVersion.* versions must be the same.', + ), ]), ); }); test('passes when jvmValues are higher than minimim', () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir, examples: []); + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + examples: [], + ); writeFakePluginBuildGradle( package, includeSourceCompat: true, @@ -464,8 +497,9 @@ dependencies { ); writeFakeManifest(package); - final List output = - await runCapturingPrint(runner, ['gradle-check']); + final List output = await runCapturingPrint(runner, [ + 'gradle-check', + ]); expect( output, @@ -475,33 +509,46 @@ dependencies { ); }); - test('passes when sourceCompatibility and targetCompatibility are specified', - () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir, examples: []); - writeFakePluginBuildGradle(package, - includeSourceCompat: true, includeTargetCompat: true); - writeFakeManifest(package); + test( + 'passes when sourceCompatibility and targetCompatibility are specified', + () async { + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + examples: [], + ); + writeFakePluginBuildGradle( + package, + includeSourceCompat: true, + includeTargetCompat: true, + ); + writeFakeManifest(package); - final List output = - await runCapturingPrint(runner, ['gradle-check']); + final List output = await runCapturingPrint(runner, [ + 'gradle-check', + ]); - expect( - output, - containsAllInOrder([ - contains('Validating android/build.gradle'), - ]), - ); - }); + expect( + output, + containsAllInOrder([ + contains('Validating android/build.gradle'), + ]), + ); + }, + ); test('passes when toolchain languageVersion is specified', () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir, examples: []); + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + examples: [], + ); writeFakePluginBuildGradle(package, includeLanguageVersion: true); writeFakeManifest(package); - final List output = - await runCapturingPrint(runner, ['gradle-check']); + final List output = await runCapturingPrint(runner, [ + 'gradle-check', + ]); expect( output, @@ -512,7 +559,7 @@ dependencies { }); test('does not require java version in examples', () async { - const String pluginName = 'a_plugin'; + const pluginName = 'a_plugin'; final RepositoryPackage package = createFakePlugin(pluginName, packagesDir); writeFakePluginBuildGradle(package, includeLanguageVersion: true); writeFakeManifest(package); @@ -520,8 +567,9 @@ dependencies { writeFakeExampleBuildGradles(example, pluginName: pluginName); writeFakeManifest(example, isApp: true); - final List output = - await runCapturingPrint(runner, ['gradle-check']); + final List output = await runCapturingPrint(runner, [ + 'gradle-check', + ]); expect( output, @@ -533,86 +581,117 @@ dependencies { }); test('fails when java compatibility version is commented out', () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir, examples: []); - writeFakePluginBuildGradle(package, - includeSourceCompat: true, - includeTargetCompat: true, - commentSourceLanguage: true); + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + examples: [], + ); + writeFakePluginBuildGradle( + package, + includeSourceCompat: true, + includeTargetCompat: true, + commentSourceLanguage: true, + ); writeFakeManifest(package); Error? commandError; final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, - containsAllInOrder([ - contains(javaIncompatabilityIndicator), - ]), + containsAllInOrder([contains(javaIncompatabilityIndicator)]), ); }); test('fails when languageVersion is commented out', () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir, examples: []); - writeFakePluginBuildGradle(package, - includeLanguageVersion: true, commentSourceLanguage: true); + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + examples: [], + ); + writeFakePluginBuildGradle( + package, + includeLanguageVersion: true, + commentSourceLanguage: true, + ); writeFakeManifest(package); Error? commandError; final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, - containsAllInOrder([ - contains(javaIncompatabilityIndicator), - ]), + containsAllInOrder([contains(javaIncompatabilityIndicator)]), ); }); - test('fails when plugin namespace does not match AndroidManifest.xml', - () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir, examples: []); - writeFakePluginBuildGradle(package, includeLanguageVersion: true); - writeFakeManifest(package, packageName: 'wrong.package.name'); + test( + 'fails when plugin namespace does not match AndroidManifest.xml', + () async { + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + examples: [], + ); + writeFakePluginBuildGradle(package, includeLanguageVersion: true); + writeFakeManifest(package, packageName: 'wrong.package.name'); - Error? commandError; - final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains( - 'build.gradle "namespace" must match the "package" attribute in AndroidManifest.xml'), - ]), - ); - }); + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains( + 'build.gradle "namespace" must match the "package" attribute in AndroidManifest.xml', + ), + ]), + ); + }, + ); test('fails when namespace is missing', () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir, examples: []); - writeFakePluginBuildGradle(package, - includeLanguageVersion: true, includeNamespace: false); + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + examples: [], + ); + writeFakePluginBuildGradle( + package, + includeLanguageVersion: true, + includeNamespace: false, + ); writeFakeManifest(package); Error? commandError; final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -624,20 +703,26 @@ dependencies { }); test('fails when namespace is missing from example', () async { - const String pluginName = 'a_plugin'; + const pluginName = 'a_plugin'; final RepositoryPackage package = createFakePlugin(pluginName, packagesDir); writeFakePluginBuildGradle(package, includeLanguageVersion: true); writeFakeManifest(package); final RepositoryPackage example = package.getExamples().first; - writeFakeExampleBuildGradles(example, - pluginName: pluginName, includeNamespace: false); + writeFakeExampleBuildGradles( + example, + pluginName: pluginName, + includeNamespace: false, + ); writeFakeManifest(example, isApp: true); Error? commandError; final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -652,44 +737,66 @@ dependencies { // point decide that we have a use case of example apps having different // app IDs and namespaces. For now, it's enforced for consistency so they // don't just accidentally diverge. - test('fails when namespace in example does not match AndroidManifest.xml', - () async { - const String pluginName = 'a_plugin'; - final RepositoryPackage package = createFakePlugin(pluginName, packagesDir); - writeFakePluginBuildGradle(package, includeLanguageVersion: true); - writeFakeManifest(package); - final RepositoryPackage example = package.getExamples().first; - writeFakeExampleBuildGradles(example, pluginName: pluginName); - writeFakeManifest(example, isApp: true, packageName: 'wrong.package.name'); + test( + 'fails when namespace in example does not match AndroidManifest.xml', + () async { + const pluginName = 'a_plugin'; + final RepositoryPackage package = createFakePlugin( + pluginName, + packagesDir, + ); + writeFakePluginBuildGradle(package, includeLanguageVersion: true); + writeFakeManifest(package); + final RepositoryPackage example = package.getExamples().first; + writeFakeExampleBuildGradles(example, pluginName: pluginName); + writeFakeManifest( + example, + isApp: true, + packageName: 'wrong.package.name', + ); - Error? commandError; - final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains( - 'build.gradle "namespace" must match the "package" attribute in AndroidManifest.xml'), - ]), - ); - }); + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains( + 'build.gradle "namespace" must match the "package" attribute in AndroidManifest.xml', + ), + ]), + ); + }, + ); test('fails when namespace is commented out', () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir, examples: []); - writeFakePluginBuildGradle(package, - includeLanguageVersion: true, commentNamespace: true); + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + examples: [], + ); + writeFakePluginBuildGradle( + package, + includeLanguageVersion: true, + commentNamespace: true, + ); writeFakeManifest(package); Error? commandError; final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -701,193 +808,245 @@ dependencies { }); test('fails when namespace is declared without "=" declaration', () async { - const String pluginName = 'a_plugin'; + const pluginName = 'a_plugin'; final RepositoryPackage package = createFakePlugin(pluginName, packagesDir); writeFakePluginBuildGradle(package, includeLanguageVersion: true); writeFakeManifest(package); final RepositoryPackage example = package.getExamples().first; - writeFakeExampleBuildGradles(example, - pluginName: pluginName, includeNameSpaceAsDeclaration: false); + writeFakeExampleBuildGradles( + example, + pluginName: pluginName, + includeNameSpaceAsDeclaration: false, + ); writeFakeManifest(example, isApp: true); Error? commandError; final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder( - [ - contains('build.gradle must set a "namespace"'), - contains('The following packages had errors:'), - ], - )); + output, + containsAllInOrder([ + contains('build.gradle must set a "namespace"'), + contains('The following packages had errors:'), + ]), + ); }); test('fails if gradle-driven lint-warnings-as-errors is missing', () async { - const String pluginName = 'a_plugin'; - final RepositoryPackage plugin = - createFakePlugin(pluginName, packagesDir, examples: []); - writeFakePluginBuildGradle(plugin, - includeLanguageVersion: true, warningsConfigured: false); + const pluginName = 'a_plugin'; + final RepositoryPackage plugin = createFakePlugin( + pluginName, + packagesDir, + examples: [], + ); + writeFakePluginBuildGradle( + plugin, + includeLanguageVersion: true, + warningsConfigured: false, + ); writeFakeManifest(plugin); Error? commandError; final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder( - [ - contains('This package is not configured to enable all ' - 'Gradle-driven lint warnings and treat them as errors.'), - contains('The following packages had errors:'), - ], - )); + output, + containsAllInOrder([ + contains( + 'This package is not configured to enable all ' + 'Gradle-driven lint warnings and treat them as errors.', + ), + contains('The following packages had errors:'), + ]), + ); }); - test('fails if plugin example javac lint-warnings-as-errors is missing', - () async { - const String pluginName = 'a_plugin'; - final RepositoryPackage plugin = createFakePlugin(pluginName, packagesDir, + test( + 'fails if plugin example javac lint-warnings-as-errors is missing', + () async { + const pluginName = 'a_plugin'; + final RepositoryPackage plugin = createFakePlugin( + pluginName, + packagesDir, platformSupport: { platformAndroid: const PlatformDetails(PlatformSupport.inline), - }); - writeFakePluginBuildGradle(plugin, includeLanguageVersion: true); - writeFakeManifest(plugin); - final RepositoryPackage example = plugin.getExamples().first; - writeFakeExampleBuildGradles(example, - pluginName: pluginName, warningsConfigured: false); - writeFakeManifest(example, isApp: true); + }, + ); + writeFakePluginBuildGradle(plugin, includeLanguageVersion: true); + writeFakeManifest(plugin); + final RepositoryPackage example = plugin.getExamples().first; + writeFakeExampleBuildGradles( + example, + pluginName: pluginName, + warningsConfigured: false, + ); + writeFakeManifest(example, isApp: true); - Error? commandError; - final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( + expect(commandError, isA()); + expect( output, - containsAllInOrder( - [ - contains('The example "example" is not configured to treat javac ' - 'lints and warnings as errors.'), - contains('The following packages had errors:'), - ], - )); - }); + containsAllInOrder([ + contains( + 'The example "example" is not configured to treat javac ' + 'lints and warnings as errors.', + ), + contains('The following packages had errors:'), + ]), + ); + }, + ); test( - 'passes if non-plugin package example javac lint-warnings-as-errors is missing', - () async { - const String packageName = 'a_package'; - final RepositoryPackage plugin = - createFakePackage(packageName, packagesDir); - final RepositoryPackage example = plugin.getExamples().first; - writeFakeExampleBuildGradles(example, - pluginName: packageName, warningsConfigured: false); - writeFakeManifest(example, isApp: true); - - final List output = - await runCapturingPrint(runner, ['gradle-check']); - - expect( - output, - containsAllInOrder( - [ - contains('Validating android/build.gradle'), - ], - )); - }); - - group('Artifact Hub check', () { - test('passes build.gradle artifact hub check when set', () async { - const String packageName = 'a_package'; - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); - writeFakePluginBuildGradle(package, includeLanguageVersion: true); - writeFakeManifest(package); - final RepositoryPackage example = package.getExamples().first; - writeFakeExampleBuildGradles(example, - pluginName: packageName, - // ignore: avoid_redundant_argument_values - includeBuildArtifactHub: true, - // ignore: avoid_redundant_argument_values - includeSettingsArtifactHub: true, - // ignore: avoid_redundant_argument_values - includeSettingsDocumentationArtifactHub: true); + 'passes if non-plugin package example javac lint-warnings-as-errors is missing', + () async { + const packageName = 'a_package'; + final RepositoryPackage plugin = createFakePackage( + packageName, + packagesDir, + ); + final RepositoryPackage example = plugin.getExamples().first; + writeFakeExampleBuildGradles( + example, + pluginName: packageName, + warningsConfigured: false, + ); writeFakeManifest(example, isApp: true); - final List output = - await runCapturingPrint(runner, ['gradle-check']); + final List output = await runCapturingPrint(runner, [ + 'gradle-check', + ]); expect( output, containsAllInOrder([ contains('Validating android/build.gradle'), - contains('Validating android/settings.gradle'), ]), ); - }); - test('fails artifact hub check when build and settings sections missing', - () async { - const String packageName = 'a_package'; - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + }, + ); + + group('Artifact Hub check', () { + test('passes build.gradle artifact hub check when set', () async { + const packageName = 'a_package'; + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); writeFakePluginBuildGradle(package, includeLanguageVersion: true); writeFakeManifest(package); final RepositoryPackage example = package.getExamples().first; writeFakeExampleBuildGradles( example, pluginName: packageName, - includeBuildArtifactHub: false, - includeSettingsArtifactHub: false, + // ignore: avoid_redundant_argument_values + includeBuildArtifactHub: true, + // ignore: avoid_redundant_argument_values + includeSettingsArtifactHub: true, + // ignore: avoid_redundant_argument_values + includeSettingsDocumentationArtifactHub: true, ); writeFakeManifest(example, isApp: true); - Error? commandError; - final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint(runner, [ + 'gradle-check', + ]); - expect(commandError, isA()); expect( output, containsAllInOrder([ - contains(GradleCheckCommand.exampleRootGradleArtifactHubString), - contains(GradleCheckCommand.exampleSettingsArtifactHubString), + contains('Validating android/build.gradle'), + contains('Validating android/settings.gradle'), ]), ); }); + test( + 'fails artifact hub check when build and settings sections missing', + () async { + const packageName = 'a_package'; + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); + writeFakePluginBuildGradle(package, includeLanguageVersion: true); + writeFakeManifest(package); + final RepositoryPackage example = package.getExamples().first; + writeFakeExampleBuildGradles( + example, + pluginName: packageName, + includeBuildArtifactHub: false, + includeSettingsArtifactHub: false, + ); + writeFakeManifest(example, isApp: true); + + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); + + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains(GradleCheckCommand.exampleRootGradleArtifactHubString), + contains(GradleCheckCommand.exampleSettingsArtifactHubString), + ]), + ); + }, + ); test('fails build.gradle artifact hub check when missing', () async { - const String packageName = 'a_package'; - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + const packageName = 'a_package'; + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); writeFakePluginBuildGradle(package, includeLanguageVersion: true); writeFakeManifest(package); final RepositoryPackage example = package.getExamples().first; - writeFakeExampleBuildGradles(example, - pluginName: packageName, - includeBuildArtifactHub: false, - // ignore: avoid_redundant_argument_values - includeSettingsArtifactHub: true); + writeFakeExampleBuildGradles( + example, + pluginName: packageName, + includeBuildArtifactHub: false, + // ignore: avoid_redundant_argument_values + includeSettingsArtifactHub: true, + ); writeFakeManifest(example, isApp: true); Error? commandError; final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -899,24 +1058,31 @@ dependencies { }); test('fails settings.gradle artifact hub check when missing', () async { - const String packageName = 'a_package'; - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + const packageName = 'a_package'; + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); writeFakePluginBuildGradle(package, includeLanguageVersion: true); writeFakeManifest(package); final RepositoryPackage example = package.getExamples().first; - writeFakeExampleBuildGradles(example, - pluginName: packageName, - // ignore: avoid_redundant_argument_values - includeBuildArtifactHub: true, - includeSettingsArtifactHub: false); + writeFakeExampleBuildGradles( + example, + pluginName: packageName, + // ignore: avoid_redundant_argument_values + includeBuildArtifactHub: true, + includeSettingsArtifactHub: false, + ); writeFakeManifest(example, isApp: true); Error? commandError; final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -931,84 +1097,105 @@ dependencies { ); }); - test('prints error for declarative method of applying gradle plugins', - () async { - const String packageName = 'a_package'; - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); - writeFakePluginBuildGradle(package, includeLanguageVersion: true); - writeFakeManifest(package); - final RepositoryPackage example = package.getExamples().first; - writeFakeExampleBuildGradles(example, + test( + 'prints error for declarative method of applying gradle plugins', + () async { + const packageName = 'a_package'; + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); + writeFakePluginBuildGradle(package, includeLanguageVersion: true); + writeFakeManifest(package); + final RepositoryPackage example = package.getExamples().first; + writeFakeExampleBuildGradles( + example, pluginName: packageName, // ignore: avoid_redundant_argument_values includeBuildArtifactHub: true, includeSettingsArtifactHub: false, // ignore: avoid_redundant_argument_values - includeSettingsDocumentationArtifactHub: true); - writeFakeManifest(example, isApp: true); - - Error? commandError; - final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); - - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains(GradleCheckCommand.exampleSettingsArtifactHubString), - ]), - ); - }); + includeSettingsDocumentationArtifactHub: true, + ); + writeFakeManifest(example, isApp: true); + + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); + + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains(GradleCheckCommand.exampleSettingsArtifactHubString), + ]), + ); + }, + ); - test('error message is printed when documentation link is missing', - () async { - const String packageName = 'a_package'; - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); - writeFakePluginBuildGradle(package, includeLanguageVersion: true); - writeFakeManifest(package); - final RepositoryPackage example = package.getExamples().first; - writeFakeExampleBuildGradles(example, + test( + 'error message is printed when documentation link is missing', + () async { + const packageName = 'a_package'; + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); + writeFakePluginBuildGradle(package, includeLanguageVersion: true); + writeFakeManifest(package); + final RepositoryPackage example = package.getExamples().first; + writeFakeExampleBuildGradles( + example, pluginName: packageName, // ignore: avoid_redundant_argument_values includeBuildArtifactHub: true, // ignore: avoid_redundant_argument_values includeSettingsArtifactHub: true, - includeSettingsDocumentationArtifactHub: false); - writeFakeManifest(example, isApp: true); - - Error? commandError; - final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); - - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains(GradleCheckCommand.artifactHubDocumentationString), - ]), - ); - }); + includeSettingsDocumentationArtifactHub: false, + ); + writeFakeManifest(example, isApp: true); + + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); + + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains(GradleCheckCommand.artifactHubDocumentationString), + ]), + ); + }, + ); }); group('Kotlin version check', () { test('passes if not set', () async { - const String packageName = 'a_package'; - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + const packageName = 'a_package'; + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); writeFakePluginBuildGradle(package, includeLanguageVersion: true); writeFakeManifest(package); final RepositoryPackage example = package.getExamples().first; writeFakeExampleBuildGradles(example, pluginName: packageName); writeFakeManifest(example, isApp: true); - final List output = - await runCapturingPrint(runner, ['gradle-check']); + final List output = await runCapturingPrint(runner, [ + 'gradle-check', + ]); expect( output, @@ -1019,18 +1206,24 @@ dependencies { }); test('passes if at the minimum allowed version', () async { - const String packageName = 'a_package'; - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + const packageName = 'a_package'; + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); writeFakePluginBuildGradle(package, includeLanguageVersion: true); writeFakeManifest(package); final RepositoryPackage example = package.getExamples().first; - writeFakeExampleBuildGradles(example, - pluginName: packageName, kotlinVersion: minKotlinVersion.toString()); + writeFakeExampleBuildGradles( + example, + pluginName: packageName, + kotlinVersion: minKotlinVersion.toString(), + ); writeFakeManifest(example, isApp: true); - final List output = - await runCapturingPrint(runner, ['gradle-check']); + final List output = await runCapturingPrint(runner, [ + 'gradle-check', + ]); expect( output, @@ -1041,18 +1234,24 @@ dependencies { }); test('passes if above the minimum allowed version', () async { - const String packageName = 'a_package'; - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + const packageName = 'a_package'; + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); writeFakePluginBuildGradle(package, includeLanguageVersion: true); writeFakeManifest(package); final RepositoryPackage example = package.getExamples().first; - writeFakeExampleBuildGradles(example, - pluginName: packageName, kotlinVersion: '99.99.0'); + writeFakeExampleBuildGradles( + example, + pluginName: packageName, + kotlinVersion: '99.99.0', + ); writeFakeManifest(example, isApp: true); - final List output = - await runCapturingPrint(runner, ['gradle-check']); + final List output = await runCapturingPrint(runner, [ + 'gradle-check', + ]); expect( output, @@ -1063,152 +1262,210 @@ dependencies { }); test('fails if below the minimum allowed version', () async { - const String packageName = 'a_package'; - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + const packageName = 'a_package'; + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); writeFakePluginBuildGradle(package, includeLanguageVersion: true); writeFakeManifest(package); final RepositoryPackage example = package.getExamples().first; - writeFakeExampleBuildGradles(example, - pluginName: packageName, kotlinVersion: '1.6.21'); + writeFakeExampleBuildGradles( + example, + pluginName: packageName, + kotlinVersion: '1.6.21', + ); writeFakeManifest(example, isApp: true); Error? commandError; final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ - contains('build.gradle sets "ext.kotlin_version" to "1.6.21". The ' - 'minimum Kotlin version that can be specified is ' - '$minKotlinVersion, for compatibility with modern dependencies.'), + contains( + 'build.gradle sets "ext.kotlin_version" to "1.6.21". The ' + 'minimum Kotlin version that can be specified is ' + '$minKotlinVersion, for compatibility with modern dependencies.', + ), ]), ); }); }); group('compileSdk check', () { - test('passes if set to a version higher than flutter.compileSdkVersion', - () async { - const String packageName = 'a_package'; - final RepositoryPackage package = - createFakePackage(packageName, packagesDir, isFlutter: true); - // Current flutter.compileSdkVersion is 36. - writeFakePluginBuildGradle(package, - includeLanguageVersion: true, compileSdk: '37'); - writeFakeManifest(package); - final RepositoryPackage example = package.getExamples().first; - writeFakeExampleBuildGradles(example, pluginName: packageName); - writeFakeManifest(example, isApp: true); - - final List output = - await runCapturingPrint(runner, ['gradle-check']); - - expect( - output, - containsAllInOrder([ - contains('Validating android/build.gradle'), - ]), - ); - }); - - test('passes if set to flutter.compileSdkVersion with Flutter 3.27+', - () async { - const String packageName = 'a_package'; - final RepositoryPackage package = createFakePackage( - packageName, packagesDir, - isFlutter: true, flutterConstraint: '>=3.27.0'); - writeFakePluginBuildGradle(package, + test( + 'passes if set to a version higher than flutter.compileSdkVersion', + () async { + const packageName = 'a_package'; + final RepositoryPackage package = createFakePackage( + packageName, + packagesDir, + isFlutter: true, + ); + // Current flutter.compileSdkVersion is 36. + writeFakePluginBuildGradle( + package, includeLanguageVersion: true, - compileSdk: 'flutter.compileSdkVersion'); - writeFakeManifest(package); - final RepositoryPackage example = package.getExamples().first; - writeFakeExampleBuildGradles(example, pluginName: packageName); - writeFakeManifest(example, isApp: true); - - final List output = - await runCapturingPrint(runner, ['gradle-check']); - - expect( - output, - containsAllInOrder([ - contains('Validating android/build.gradle'), - ]), - ); - }); - - test('fails if set to a version lower than flutter.compileSdkVersion', - () async { - const String packageName = 'a_package'; - final RepositoryPackage package = - createFakePackage(packageName, packagesDir, isFlutter: true); - // Current flutter.compileSdkVersion is 36. - const String minCompileSdkVersion = '36'; - const String testCompileSdkVersion = '35'; - writeFakePluginBuildGradle(package, - includeLanguageVersion: true, compileSdk: testCompileSdkVersion); - writeFakeManifest(package); - final RepositoryPackage example = package.getExamples().first; - writeFakeExampleBuildGradles(example, pluginName: packageName); - writeFakeManifest(example, isApp: true); - - Error? commandError; - final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); - - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('compileSdk version $testCompileSdkVersion is too low. ' - 'Minimum required version is $minCompileSdkVersion.'), - ]), - ); - }); + compileSdk: '37', + ); + writeFakeManifest(package); + final RepositoryPackage example = package.getExamples().first; + writeFakeExampleBuildGradles(example, pluginName: packageName); + writeFakeManifest(example, isApp: true); + + final List output = await runCapturingPrint(runner, [ + 'gradle-check', + ]); + + expect( + output, + containsAllInOrder([ + contains('Validating android/build.gradle'), + ]), + ); + }, + ); - test('fails if set to flutter.compileSdkVersion with Flutter <3.27', - () async { - const String packageName = 'a_package'; - final RepositoryPackage package = createFakePackage( - packageName, packagesDir, - isFlutter: true, flutterConstraint: '>=3.24.0'); - writeFakePluginBuildGradle(package, + test( + 'passes if set to flutter.compileSdkVersion with Flutter 3.27+', + () async { + const packageName = 'a_package'; + final RepositoryPackage package = createFakePackage( + packageName, + packagesDir, + isFlutter: true, + flutterConstraint: '>=3.27.0', + ); + writeFakePluginBuildGradle( + package, includeLanguageVersion: true, - compileSdk: 'flutter.compileSdkVersion'); - writeFakeManifest(package); - final RepositoryPackage example = package.getExamples().first; - writeFakeExampleBuildGradles(example, pluginName: packageName); - writeFakeManifest(example, isApp: true); + compileSdk: 'flutter.compileSdkVersion', + ); + writeFakeManifest(package); + final RepositoryPackage example = package.getExamples().first; + writeFakeExampleBuildGradles(example, pluginName: packageName); + writeFakeManifest(example, isApp: true); + + final List output = await runCapturingPrint(runner, [ + 'gradle-check', + ]); + + expect( + output, + containsAllInOrder([ + contains('Validating android/build.gradle'), + ]), + ); + }, + ); - Error? commandError; - final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + test( + 'fails if set to a version lower than flutter.compileSdkVersion', + () async { + const packageName = 'a_package'; + final RepositoryPackage package = createFakePackage( + packageName, + packagesDir, + isFlutter: true, + ); + // Current flutter.compileSdkVersion is 36. + const minCompileSdkVersion = '36'; + const testCompileSdkVersion = '35'; + writeFakePluginBuildGradle( + package, + includeLanguageVersion: true, + compileSdk: testCompileSdkVersion, + ); + writeFakeManifest(package); + final RepositoryPackage example = package.getExamples().first; + writeFakeExampleBuildGradles(example, pluginName: packageName); + writeFakeManifest(example, isApp: true); + + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); + + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains( + 'compileSdk version $testCompileSdkVersion is too low. ' + 'Minimum required version is $minCompileSdkVersion.', + ), + ]), + ); + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('Use of flutter.compileSdkVersion requires a minimum ' + test( + 'fails if set to flutter.compileSdkVersion with Flutter <3.27', + () async { + const packageName = 'a_package'; + final RepositoryPackage package = createFakePackage( + packageName, + packagesDir, + isFlutter: true, + flutterConstraint: '>=3.24.0', + ); + writeFakePluginBuildGradle( + package, + includeLanguageVersion: true, + compileSdk: 'flutter.compileSdkVersion', + ); + writeFakeManifest(package); + final RepositoryPackage example = package.getExamples().first; + writeFakeExampleBuildGradles(example, pluginName: packageName); + writeFakeManifest(example, isApp: true); + + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); + + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains( + 'Use of flutter.compileSdkVersion requires a minimum ' 'Flutter version of 3.27, but this package currently supports ' - '3.24.0'), - ]), - ); - }); + '3.24.0', + ), + ]), + ); + }, + ); test('fails if uses the legacy key', () async { - const String packageName = 'a_package'; - final RepositoryPackage package = - createFakePackage(packageName, packagesDir, isFlutter: true); - writeFakePluginBuildGradle(package, - includeLanguageVersion: true, useDeprecatedCompileSdkVersion: true); + const packageName = 'a_package'; + final RepositoryPackage package = createFakePackage( + packageName, + packagesDir, + isFlutter: true, + ); + writeFakePluginBuildGradle( + package, + includeLanguageVersion: true, + useDeprecatedCompileSdkVersion: true, + ); writeFakeManifest(package); final RepositoryPackage example = package.getExamples().first; writeFakeExampleBuildGradles(example, pluginName: packageName); @@ -1216,37 +1473,54 @@ dependencies { Error? commandError; final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ - contains('Please replace the deprecated "compileSdkVersion" setting ' - 'with the newer "compileSdk"'), + contains( + 'Please replace the deprecated "compileSdkVersion" setting ' + 'with the newer "compileSdk"', + ), ]), ); }); test('fails if compileSdk uses the method assignment', () async { - const String packageName = 'a_package'; - final RepositoryPackage package = - createFakePackage(packageName, packagesDir, isFlutter: true); - writeFakePluginBuildGradle(package, - includeLanguageVersion: true, usePropertyAssignment: false); + const packageName = 'a_package'; + final RepositoryPackage package = createFakePackage( + packageName, + packagesDir, + isFlutter: true, + ); + writeFakePluginBuildGradle( + package, + includeLanguageVersion: true, + usePropertyAssignment: false, + ); writeFakeManifest(package); final RepositoryPackage example = package.getExamples().first; - writeFakeExampleBuildGradles(example, - pluginName: packageName, usePropertyAssignment: false); + writeFakeExampleBuildGradles( + example, + pluginName: packageName, + usePropertyAssignment: false, + ); writeFakeManifest(example, isApp: true); Error? commandError; final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -1260,8 +1534,11 @@ dependencies { group('kotlinOptions check', () { test('passes when kotlin options are specified', () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir, examples: []); + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + examples: [], + ); writeFakePluginBuildGradle( package, includeLanguageVersion: true, @@ -1270,8 +1547,9 @@ dependencies { ); writeFakeManifest(package); - final List output = - await runCapturingPrint(runner, ['gradle-check']); + final List output = await runCapturingPrint(runner, [ + 'gradle-check', + ]); expect( output, @@ -1282,8 +1560,11 @@ dependencies { }); test('passes when kotlin options are not specified', () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir, examples: []); + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + examples: [], + ); writeFakePluginBuildGradle( package, includeLanguageVersion: true, @@ -1291,8 +1572,9 @@ dependencies { ); writeFakeManifest(package); - final List output = - await runCapturingPrint(runner, ['gradle-check']); + final List output = await runCapturingPrint(runner, [ + 'gradle-check', + ]); expect( output, @@ -1303,8 +1585,11 @@ dependencies { }); test('passes when kotlin options commented out', () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir, examples: []); + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + examples: [], + ); writeFakePluginBuildGradle( package, includeLanguageVersion: true, @@ -1312,8 +1597,9 @@ dependencies { ); writeFakeManifest(package); - final List output = - await runCapturingPrint(runner, ['gradle-check']); + final List output = await runCapturingPrint(runner, [ + 'gradle-check', + ]); expect( output, @@ -1324,8 +1610,11 @@ dependencies { }); test('fails when kotlin options uses string jvm version', () async { - final RepositoryPackage package = - createFakePlugin('a_plugin', packagesDir, examples: []); + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir, + examples: [], + ); writeFakePluginBuildGradle( package, includeLanguageVersion: true, @@ -1335,16 +1624,20 @@ dependencies { Error? commandError; final List output = await runCapturingPrint( - runner, ['gradle-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['gradle-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - 'build.gradle(.kts) sets jvmTarget then it must use JavaVersion syntax'), + 'build.gradle(.kts) sets jvmTarget then it must use JavaVersion syntax', + ), ]), ); }); diff --git a/script/tool/test/license_check_command_test.dart b/script/tool/test/license_check_command_test.dart index 51b750f8bd7a..510eeda62227 100644 --- a/script/tool/test/license_check_command_test.dart +++ b/script/tool/test/license_check_command_test.dart @@ -29,13 +29,15 @@ void main() { configureBaseCommandMocks(platform: platform); root = packagesDir.parent; - final LicenseCheckCommand command = LicenseCheckCommand( + final command = LicenseCheckCommand( packagesDir, platform: platform, gitDir: gitDir, ); - runner = - CommandRunner('license_test', 'Test for $LicenseCheckCommand'); + runner = CommandRunner( + 'license_test', + 'Test for $LicenseCheckCommand', + ); runner.addCommand(command); }); @@ -57,11 +59,11 @@ void main() { ], bool useCrlf = false, }) { - final List lines = ['$prefix$comment$copyright']; - for (final String line in license) { + final lines = ['$prefix$comment$copyright']; + for (final line in license) { lines.add('$comment$line'); } - final String newline = useCrlf ? '\r\n' : '\n'; + final newline = useCrlf ? '\r\n' : '\n'; file.writeAsStringSync(lines.join(newline) + suffix + newline); } @@ -71,18 +73,21 @@ void main() { final String fileList = root .listSync(recursive: true, followLinks: false) .whereType() - .map((File f) => p.posix - .joinAll(p.split(p.relative(f.absolute.path, from: root.path)))) + .map( + (File f) => p.posix.joinAll( + p.split(p.relative(f.absolute.path, from: root.path)), + ), + ) .join('\n'); gitProcessRunner.mockProcessesForExecutable['git-ls-files'] = [ - FakeProcessInfo(MockProcess(stdout: '$fileList\n')), - ]; + FakeProcessInfo(MockProcess(stdout: '$fileList\n')), + ]; } test('looks at only expected extensions', () async { - final Map extensions = { + final extensions = { 'c': true, 'cc': true, 'cpp': true, @@ -101,27 +106,31 @@ void main() { 'yaml': false, }; - const String filenameBase = 'a_file'; + const filenameBase = 'a_file'; for (final String fileExtension in extensions.keys) { root.childFile('$filenameBase.$fileExtension').createSync(); } mockGitFilesListWithAllFiles(root); final List output = await runCapturingPrint( - runner, ['license-check'], errorHandler: (Error e) { - // Ignore failure; the files are empty so the check is expected to fail, - // but this test isn't for that behavior. - }); + runner, + ['license-check'], + errorHandler: (Error e) { + // Ignore failure; the files are empty so the check is expected to fail, + // but this test isn't for that behavior. + }, + ); extensions.forEach((String fileExtension, bool shouldCheck) { - final Matcher logLineMatcher = - contains('Checking $filenameBase.$fileExtension'); + final Matcher logLineMatcher = contains( + 'Checking $filenameBase.$fileExtension', + ); expect(output, shouldCheck ? logLineMatcher : isNot(logLineMatcher)); }); }); test('ignore list overrides extension matches', () async { - final List ignoredFiles = [ + final ignoredFiles = [ // Ignored base names. 'flutter_export_environment.sh', 'GeneratedPluginRegistrant.java', @@ -136,21 +145,22 @@ void main() { 'resource.h', ]; - for (final String name in ignoredFiles) { + for (final name in ignoredFiles) { root.childFile(name).createSync(); } mockGitFilesListWithAllFiles(root); - final List output = - await runCapturingPrint(runner, ['license-check']); + final List output = await runCapturingPrint(runner, [ + 'license-check', + ]); - for (final String name in ignoredFiles) { + for (final name in ignoredFiles) { expect(output, isNot(contains('Checking $name'))); } }); test('ignores submodules', () async { - const String submoduleName = 'a_submodule'; + const submoduleName = 'a_submodule'; final File submoduleSpec = root.childFile('.gitmodules'); submoduleSpec.writeAsStringSync(''' @@ -159,19 +169,20 @@ void main() { url = https://github.com/foo/$submoduleName '''); - const List submoduleFiles = [ + const submoduleFiles = [ '$submoduleName/foo.dart', '$submoduleName/a/b/bar.dart', '$submoduleName/LICENSE', ]; - for (final String filePath in submoduleFiles) { + for (final filePath in submoduleFiles) { root.childFile(filePath).createSync(recursive: true); } - final List output = - await runCapturingPrint(runner, ['license-check']); + final List output = await runCapturingPrint(runner, [ + 'license-check', + ]); - for (final String filePath in submoduleFiles) { + for (final filePath in submoduleFiles) { expect(output, isNot(contains('Checking $filePath'))); } }); @@ -179,9 +190,9 @@ void main() { test('ignores files that are not checked in', () async { mockGitFilesListWithAllFiles(root); // Add files after creating the mock output from created files. - final Directory packageDir = root - .childDirectory('FlutterGeneratedPluginSwiftPackage') - ..createSync(); + final Directory packageDir = root.childDirectory( + 'FlutterGeneratedPluginSwiftPackage', + )..createSync(); packageDir.childFile('Package.swift').createSync(); packageDir .childDirectory('Sources') @@ -189,11 +200,14 @@ void main() { .childFile('FlutterGeneratedPluginSwiftPackage.swift') .createSync(recursive: true); - final List output = - await runCapturingPrint(runner, ['license-check']); + final List output = await runCapturingPrint(runner, [ + 'license-check', + ]); - expect(output, - isNot(contains('Checking FlutterGeneratedPluginSwiftPackage'))); + expect( + output, + isNot(contains('Checking FlutterGeneratedPluginSwiftPackage')), + ); }); test('passes if all checked files have license blocks', () async { @@ -204,16 +218,18 @@ void main() { notChecked.createSync(); mockGitFilesListWithAllFiles(root); - final List output = - await runCapturingPrint(runner, ['license-check']); + final List output = await runCapturingPrint(runner, [ + 'license-check', + ]); // Sanity check that the test did actually check a file. expect( - output, - containsAllInOrder([ - contains('Checking checked.cc'), - contains('All files passed validation!'), - ])); + output, + containsAllInOrder([ + contains('Checking checked.cc'), + contains('All files passed validation!'), + ]), + ); }); test('passes correct license blocks on Windows', () async { @@ -222,16 +238,18 @@ void main() { writeLicense(checked, useCrlf: true); mockGitFilesListWithAllFiles(root); - final List output = - await runCapturingPrint(runner, ['license-check']); + final List output = await runCapturingPrint(runner, [ + 'license-check', + ]); // Sanity check that the test did actually check a file. expect( - output, - containsAllInOrder([ - contains('Checking checked.cc'), - contains('All files passed validation!'), - ])); + output, + containsAllInOrder([ + contains('Checking checked.cc'), + contains('All files passed validation!'), + ]), + ); }); test('handles the comment styles for all supported languages', () async { @@ -246,18 +264,20 @@ void main() { writeLicense(fileC, comment: '', prefix: ''); mockGitFilesListWithAllFiles(root); - final List output = - await runCapturingPrint(runner, ['license-check']); + final List output = await runCapturingPrint(runner, [ + 'license-check', + ]); // Sanity check that the test did actually check the files. expect( - output, - containsAllInOrder([ - contains('Checking file_a.cc'), - contains('Checking file_b.sh'), - contains('Checking file_c.html'), - contains('All files passed validation!'), - ])); + output, + containsAllInOrder([ + contains('Checking file_a.cc'), + contains('Checking file_b.sh'), + contains('Checking file_c.html'), + contains('All files passed validation!'), + ]), + ); }); test('fails if any checked files are missing license blocks', () async { @@ -273,20 +293,25 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['license-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['license-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); // Failure should give information about the problematic files. expect( - output, - containsAllInOrder([ - contains( - 'The license block for these files is missing or incorrect:'), - contains(' bad.cc'), - contains(' bad.h'), - ])); + output, + containsAllInOrder([ + contains( + 'The license block for these files is missing or incorrect:', + ), + contains(' bad.cc'), + contains(' bad.h'), + ]), + ); // Failure shouldn't print the success message. expect(output, isNot(contains(contains('All files passed validation!')))); }); @@ -302,19 +327,24 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['license-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['license-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); // Failure should give information about the problematic files. expect( - output, - containsAllInOrder([ - contains( - 'The license block for these files is missing or incorrect:'), - contains(' bad.cc'), - ])); + output, + containsAllInOrder([ + contains( + 'The license block for these files is missing or incorrect:', + ), + contains(' bad.cc'), + ]), + ); // Failure shouldn't print the success message. expect(output, isNot(contains(contains('All files passed validation!')))); }); @@ -330,82 +360,107 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['license-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['license-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); // Failure should give information about the problematic files. expect( - output, - containsAllInOrder([ - contains( - 'The license block for these files is missing or incorrect:'), - contains(' bad.cc'), - ])); + output, + containsAllInOrder([ + contains( + 'The license block for these files is missing or incorrect:', + ), + contains(' bad.cc'), + ]), + ); // Failure shouldn't print the success message. expect(output, isNot(contains(contains('All files passed validation!')))); }); - test('fails if any checked files are using the older boilerplate format', - () async { - final File good = root.childFile('good.cc'); - good.createSync(); - writeLicense(good); - final File bad = root.childFile('bad.cc'); - bad.createSync(); - bad.writeAsStringSync(''' + test( + 'fails if any checked files are using the older boilerplate format', + () async { + final File good = root.childFile('good.cc'); + good.createSync(); + writeLicense(good); + final File bad = root.childFile('bad.cc'); + bad.createSync(); + bad.writeAsStringSync(''' // 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. '''); - mockGitFilesListWithAllFiles(root); + mockGitFilesListWithAllFiles(root); - Error? commandError; - final List output = await runCapturingPrint( - runner, ['license-check'], errorHandler: (Error e) { - commandError = e; - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['license-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - // Failure should give information about the problematic files. - expect( + expect(commandError, isA()); + // Failure should give information about the problematic files. + expect( output, containsAllInOrder([ contains( - 'The license block for these files is missing or incorrect:'), + 'The license block for these files is missing or incorrect:', + ), contains(' bad.cc'), - ])); - // Failure shouldn't print the success message. - expect(output, isNot(contains(contains('All files passed validation!')))); - }); - - test('fails if any third-party code is not in a third_party directory', - () async { - final File thirdPartyFile = root.childFile('third_party.cc'); - thirdPartyFile.createSync(); - writeLicense(thirdPartyFile, copyright: 'Copyright 2017 Someone Else'); - mockGitFilesListWithAllFiles(root); - - Error? commandError; - final List output = await runCapturingPrint( - runner, ['license-check'], errorHandler: (Error e) { - commandError = e; - }); - - expect(commandError, isA()); - // Failure should give information about the problematic files. - expect( + ]), + ); + // Failure shouldn't print the success message. + expect( + output, + isNot(contains(contains('All files passed validation!'))), + ); + }, + ); + + test( + 'fails if any third-party code is not in a third_party directory', + () async { + final File thirdPartyFile = root.childFile('third_party.cc'); + thirdPartyFile.createSync(); + writeLicense(thirdPartyFile, copyright: 'Copyright 2017 Someone Else'); + mockGitFilesListWithAllFiles(root); + + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['license-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); + + expect(commandError, isA()); + // Failure should give information about the problematic files. + expect( output, containsAllInOrder([ contains( - 'The license block for these files is missing or incorrect:'), + 'The license block for these files is missing or incorrect:', + ), contains(' third_party.cc'), - ])); - // Failure shouldn't print the success message. - expect(output, isNot(contains(contains('All files passed validation!')))); - }); + ]), + ); + // Failure shouldn't print the success message. + expect( + output, + isNot(contains(contains('All files passed validation!'))), + ); + }, + ); test('succeeds for third-party code in a third_party directory', () async { final File thirdPartyFile = root @@ -415,24 +470,28 @@ void main() { .childDirectory('third_party') .childFile('file.cc'); thirdPartyFile.createSync(recursive: true); - writeLicense(thirdPartyFile, - copyright: 'Copyright 2017 Workiva Inc.', - license: [ - 'Licensed under the Apache License, Version 2.0 (the "License");', - 'you may not use this file except in compliance with the License.' - ]); + writeLicense( + thirdPartyFile, + copyright: 'Copyright 2017 Workiva Inc.', + license: [ + 'Licensed under the Apache License, Version 2.0 (the "License");', + 'you may not use this file except in compliance with the License.', + ], + ); mockGitFilesListWithAllFiles(root); - final List output = - await runCapturingPrint(runner, ['license-check']); + final List output = await runCapturingPrint(runner, [ + 'license-check', + ]); // Sanity check that the test did actually check the file. expect( - output, - containsAllInOrder([ - contains('Checking a_plugin/lib/src/third_party/file.cc'), - contains('All files passed validation!'), - ])); + output, + containsAllInOrder([ + contains('Checking a_plugin/lib/src/third_party/file.cc'), + contains('All files passed validation!'), + ]), + ); }); test('allows first-party code in a third_party directory', () async { @@ -446,16 +505,18 @@ void main() { writeLicense(firstPartyFileInThirdParty); mockGitFilesListWithAllFiles(root); - final List output = - await runCapturingPrint(runner, ['license-check']); + final List output = await runCapturingPrint(runner, [ + 'license-check', + ]); // Sanity check that the test did actually check the file. expect( - output, - containsAllInOrder([ - contains('Checking a_plugin/lib/src/third_party/first_party.cc'), - contains('All files passed validation!'), - ])); + output, + containsAllInOrder([ + contains('Checking a_plugin/lib/src/third_party/first_party.cc'), + contains('All files passed validation!'), + ]), + ); }); test('fails for licenses that the tool does not expect', () async { @@ -464,131 +525,166 @@ void main() { writeLicense(good); final File bad = root.childDirectory('third_party').childFile('bad.cc'); bad.createSync(recursive: true); - writeLicense(bad, license: [ - 'This program is free software: you can redistribute it and/or modify', - 'it under the terms of the GNU General Public License', - ]); - mockGitFilesListWithAllFiles(root); - - Error? commandError; - final List output = await runCapturingPrint( - runner, ['license-check'], errorHandler: (Error e) { - commandError = e; - }); - - expect(commandError, isA()); - // Failure should give information about the problematic files. - expect( - output, - containsAllInOrder([ - contains( - 'No recognized license was found for the following third-party files:'), - contains(' third_party/bad.cc'), - ])); - // Failure shouldn't print the success message. - expect(output, isNot(contains(contains('All files passed validation!')))); - }); - - test('Apache is not recognized for new authors without validation changes', - () async { - final File good = root.childFile('good.cc'); - good.createSync(); - writeLicense(good); - final File bad = root.childDirectory('third_party').childFile('bad.cc'); - bad.createSync(recursive: true); writeLicense( bad, - copyright: 'Copyright 2017 Some New Authors.', license: [ - 'Licensed under the Apache License, Version 2.0 (the "License");', - 'you may not use this file except in compliance with the License.' + 'This program is free software: you can redistribute it and/or modify', + 'it under the terms of the GNU General Public License', ], ); mockGitFilesListWithAllFiles(root); Error? commandError; final List output = await runCapturingPrint( - runner, ['license-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['license-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); // Failure should give information about the problematic files. expect( - output, - containsAllInOrder([ - contains( - 'No recognized license was found for the following third-party files:'), - contains(' third_party/bad.cc'), - ])); + output, + containsAllInOrder([ + contains( + 'No recognized license was found for the following third-party files:', + ), + contains(' third_party/bad.cc'), + ]), + ); // Failure shouldn't print the success message. expect(output, isNot(contains(contains('All files passed validation!')))); }); - test('passes if all first-party LICENSE files are correctly formatted', - () async { - final File license = root.childFile('LICENSE'); - license.createSync(); - license.writeAsStringSync(_correctLicenseFileText); - mockGitFilesListWithAllFiles(root); - - final List output = - await runCapturingPrint(runner, ['license-check']); - - // Sanity check that the test did actually check the file. - expect( + test( + 'Apache is not recognized for new authors without validation changes', + () async { + final File good = root.childFile('good.cc'); + good.createSync(); + writeLicense(good); + final File bad = root.childDirectory('third_party').childFile('bad.cc'); + bad.createSync(recursive: true); + writeLicense( + bad, + copyright: 'Copyright 2017 Some New Authors.', + license: [ + 'Licensed under the Apache License, Version 2.0 (the "License");', + 'you may not use this file except in compliance with the License.', + ], + ); + mockGitFilesListWithAllFiles(root); + + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['license-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); + + expect(commandError, isA()); + // Failure should give information about the problematic files. + expect( + output, + containsAllInOrder([ + contains( + 'No recognized license was found for the following third-party files:', + ), + contains(' third_party/bad.cc'), + ]), + ); + // Failure shouldn't print the success message. + expect( + output, + isNot(contains(contains('All files passed validation!'))), + ); + }, + ); + + test( + 'passes if all first-party LICENSE files are correctly formatted', + () async { + final File license = root.childFile('LICENSE'); + license.createSync(); + license.writeAsStringSync(_correctLicenseFileText); + mockGitFilesListWithAllFiles(root); + + final List output = await runCapturingPrint(runner, [ + 'license-check', + ]); + + // Sanity check that the test did actually check the file. + expect( output, containsAllInOrder([ contains('Checking LICENSE'), contains('All files passed validation!'), - ])); - }); + ]), + ); + }, + ); test('passes correct LICENSE files on Windows', () async { final File license = root.childFile('LICENSE'); license.createSync(); - license - .writeAsStringSync(_correctLicenseFileText.replaceAll('\n', '\r\n')); + license.writeAsStringSync( + _correctLicenseFileText.replaceAll('\n', '\r\n'), + ); mockGitFilesListWithAllFiles(root); - final List output = - await runCapturingPrint(runner, ['license-check']); + final List output = await runCapturingPrint(runner, [ + 'license-check', + ]); // Sanity check that the test did actually check the file. expect( - output, - containsAllInOrder([ - contains('Checking LICENSE'), - contains('All files passed validation!'), - ])); + output, + containsAllInOrder([ + contains('Checking LICENSE'), + contains('All files passed validation!'), + ]), + ); }); - test('fails if any first-party LICENSE files are incorrectly formatted', - () async { - final File license = root.childFile('LICENSE'); - license.createSync(); - license.writeAsStringSync(_incorrectLicenseFileText); - mockGitFilesListWithAllFiles(root); - - Error? commandError; - final List output = await runCapturingPrint( - runner, ['license-check'], errorHandler: (Error e) { - commandError = e; - }); - - expect(commandError, isA()); - expect(output, isNot(contains(contains('All files passed validation!')))); - }); + test( + 'fails if any first-party LICENSE files are incorrectly formatted', + () async { + final File license = root.childFile('LICENSE'); + license.createSync(); + license.writeAsStringSync(_incorrectLicenseFileText); + mockGitFilesListWithAllFiles(root); + + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['license-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); + + expect(commandError, isA()); + expect( + output, + isNot(contains(contains('All files passed validation!'))), + ); + }, + ); test('ignores third-party LICENSE format', () async { - final File license = - root.childDirectory('third_party').childFile('LICENSE'); + final File license = root + .childDirectory('third_party') + .childFile('LICENSE'); license.createSync(recursive: true); license.writeAsStringSync(_incorrectLicenseFileText); mockGitFilesListWithAllFiles(root); - final List output = - await runCapturingPrint(runner, ['license-check']); + final List output = await runCapturingPrint(runner, [ + 'license-check', + ]); // The file shouldn't be checked. expect(output, isNot(contains(contains('Checking third_party/LICENSE')))); @@ -607,27 +703,34 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['license-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['license-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Checking LICENSE'), - contains('Checking bad.cc'), - contains('Checking third_party/bad.cc'), - contains( - 'The following LICENSE files do not follow the expected format:'), - contains(' LICENSE'), - contains( - 'The license block for these files is missing or incorrect:'), - contains(' bad.cc'), - contains( - 'No recognized license was found for the following third-party files:'), - contains(' third_party/bad.cc'), - ])); + output, + containsAllInOrder([ + contains('Checking LICENSE'), + contains('Checking bad.cc'), + contains('Checking third_party/bad.cc'), + contains( + 'The following LICENSE files do not follow the expected format:', + ), + contains(' LICENSE'), + contains( + 'The license block for these files is missing or incorrect:', + ), + contains(' bad.cc'), + contains( + 'No recognized license was found for the following third-party files:', + ), + contains(' third_party/bad.cc'), + ]), + ); }); test('passes if Package.swift has license blocks', () async { @@ -635,16 +738,18 @@ void main() { checked.createSync(); writeLicense(checked, prefix: '// swift-tools-version: 5.9\n'); mockGitFilesListWithAllFiles(root); - final List output = - await runCapturingPrint(runner, ['license-check']); + final List output = await runCapturingPrint(runner, [ + 'license-check', + ]); // Sanity check that the test did actually check a file. expect( - output, - containsAllInOrder([ - contains('Checking Package.swift'), - contains('All files passed validation!'), - ])); + output, + containsAllInOrder([ + contains('Checking Package.swift'), + contains('All files passed validation!'), + ]), + ); }); }); } diff --git a/script/tool/test/list_command_test.dart b/script/tool/test/list_command_test.dart index d347530ed3f7..61f86f1c66d7 100644 --- a/script/tool/test/list_command_test.dart +++ b/script/tool/test/list_command_test.dart @@ -20,8 +20,7 @@ void main() { mockPlatform = MockPlatform(); (:packagesDir, processRunner: _, gitProcessRunner: _, gitDir: _) = configureBaseCommandMocks(platform: mockPlatform); - final ListCommand command = - ListCommand(packagesDir, platform: mockPlatform); + final command = ListCommand(packagesDir, platform: mockPlatform); runner = CommandRunner('list_test', 'Test for $ListCommand'); runner.addCommand(command); @@ -31,26 +30,30 @@ void main() { createFakePackage('package1', packagesDir); createFakePlugin('plugin2', packagesDir); - final List plugins = - await runCapturingPrint(runner, ['list', '--type=package']); + final List plugins = await runCapturingPrint(runner, [ + 'list', + '--type=package', + ]); expect( plugins, - orderedEquals([ - '/packages/package1', - '/packages/plugin2', - ]), + orderedEquals(['/packages/package1', '/packages/plugin2']), ); }); test('lists examples', () async { createFakePlugin('plugin1', packagesDir); - createFakePlugin('plugin2', packagesDir, - examples: ['example1', 'example2']); + createFakePlugin( + 'plugin2', + packagesDir, + examples: ['example1', 'example2'], + ); createFakePlugin('plugin3', packagesDir, examples: []); - final List examples = - await runCapturingPrint(runner, ['list', '--type=example']); + final List examples = await runCapturingPrint(runner, [ + 'list', + '--type=example', + ]); expect( examples, @@ -64,12 +67,17 @@ void main() { test('lists packages and subpackages', () async { createFakePackage('package1', packagesDir); - createFakePlugin('plugin2', packagesDir, - examples: ['example1', 'example2']); + createFakePlugin( + 'plugin2', + packagesDir, + examples: ['example1', 'example2'], + ); createFakePlugin('plugin3', packagesDir, examples: []); - final List packages = await runCapturingPrint( - runner, ['list', '--type=package-or-subpackage']); + final List packages = await runCapturingPrint(runner, [ + 'list', + '--type=package-or-subpackage', + ]); expect( packages, @@ -86,12 +94,17 @@ void main() { test('lists files', () async { createFakePlugin('plugin1', packagesDir); - createFakePlugin('plugin2', packagesDir, - examples: ['example1', 'example2']); + createFakePlugin( + 'plugin2', + packagesDir, + examples: ['example1', 'example2'], + ); createFakePlugin('plugin3', packagesDir, examples: []); - final List examples = - await runCapturingPrint(runner, ['list', '--type=file']); + final List examples = await runCapturingPrint(runner, [ + 'list', + '--type=file', + ]); expect( examples, @@ -120,15 +133,17 @@ void main() { // Create a federated plugin by creating a directory under the packages // directory with several packages underneath. - final Directory federatedPluginDir = - packagesDir.childDirectory('my_plugin')..createSync(); + final Directory federatedPluginDir = packagesDir.childDirectory( + 'my_plugin', + )..createSync(); createFakePlugin('my_plugin', federatedPluginDir); createFakePlugin('my_plugin_web', federatedPluginDir); createFakePlugin('my_plugin_macos', federatedPluginDir); // Test without specifying `--type`. - final List plugins = - await runCapturingPrint(runner, ['list']); + final List plugins = await runCapturingPrint(runner, [ + 'list', + ]); expect( plugins, @@ -146,23 +161,23 @@ void main() { // Create a federated plugin by creating a directory under the packages // directory with several packages underneath. - final Directory federatedPluginDir = - packagesDir.childDirectory('my_plugin')..createSync(); + final Directory federatedPluginDir = packagesDir.childDirectory( + 'my_plugin', + )..createSync(); createFakePlugin('my_plugin', federatedPluginDir); createFakePlugin('my_plugin_web', federatedPluginDir); createFakePlugin('my_plugin_macos', federatedPluginDir); - List plugins = await runCapturingPrint( - runner, ['list', '--packages=plugin1']); - expect( - plugins, - unorderedEquals([ - '/packages/plugin1', - ]), - ); + List plugins = await runCapturingPrint(runner, [ + 'list', + '--packages=plugin1', + ]); + expect(plugins, unorderedEquals(['/packages/plugin1'])); - plugins = await runCapturingPrint( - runner, ['list', '--packages=my_plugin']); + plugins = await runCapturingPrint(runner, [ + 'list', + '--packages=my_plugin', + ]); expect( plugins, unorderedEquals([ @@ -172,17 +187,19 @@ void main() { ]), ); - plugins = await runCapturingPrint( - runner, ['list', '--packages=my_plugin/my_plugin_web']); + plugins = await runCapturingPrint(runner, [ + 'list', + '--packages=my_plugin/my_plugin_web', + ]); expect( plugins, - unorderedEquals([ - '/packages/my_plugin/my_plugin_web', - ]), + unorderedEquals(['/packages/my_plugin/my_plugin_web']), ); - plugins = await runCapturingPrint(runner, - ['list', '--packages=my_plugin/my_plugin_web,plugin1']); + plugins = await runCapturingPrint(runner, [ + 'list', + '--packages=my_plugin/my_plugin_web,plugin1', + ]); expect( plugins, unorderedEquals([ diff --git a/script/tool/test/make_deps_path_based_command_test.dart b/script/tool/test/make_deps_path_based_command_test.dart index aadccf9721f8..b945c676e70a 100644 --- a/script/tool/test/make_deps_path_based_command_test.dart +++ b/script/tool/test/make_deps_path_based_command_test.dart @@ -26,18 +26,22 @@ void main() { .childDirectory('third_party') .childDirectory('packages'); - final MakeDepsPathBasedCommand command = - MakeDepsPathBasedCommand(packagesDir, gitDir: gitDir); + final command = MakeDepsPathBasedCommand(packagesDir, gitDir: gitDir); runner = CommandRunner( - 'make-deps-path-based_command', 'Test for $MakeDepsPathBasedCommand'); + 'make-deps-path-based_command', + 'Test for $MakeDepsPathBasedCommand', + ); runner.addCommand(command); }); /// Adds dummy 'dependencies:' entries for each package in [dependencies] /// to [package]. - void addDependencies(RepositoryPackage package, Iterable dependencies, - {String constraint = '<2.0.0'}) { + void addDependencies( + RepositoryPackage package, + Iterable dependencies, { + String constraint = '<2.0.0', + }) { final List lines = package.pubspecFile.readAsLinesSync(); final int dependenciesStartIndex = lines.indexOf('dependencies:'); assert(dependenciesStartIndex != -1); @@ -51,8 +55,10 @@ void main() { /// Adds dummy 'dependencies:' entries for each package in [dependencies] /// to [package], using a path-based dependency. void addPathDependencies( - RepositoryPackage package, Iterable dependencies, - {required String relativePathBase}) { + RepositoryPackage package, + Iterable dependencies, { + required String relativePathBase, + }) { final List lines = package.pubspecFile.readAsLinesSync(); final int dependenciesStartIndex = lines.indexOf('dependencies:'); assert(dependenciesStartIndex != -1); @@ -66,8 +72,10 @@ void main() { /// Adds a 'dev_dependencies:' section with entries for each package in /// [dependencies] to [package]. void addDevDependenciesSection( - RepositoryPackage package, Iterable devDependencies, - {String constraint = '<2.0.0'}) { + RepositoryPackage package, + Iterable devDependencies, { + String constraint = '<2.0.0', + }) { final String originalContent = package.pubspecFile.readAsStringSync(); package.pubspecFile.writeAsStringSync(''' $originalContent @@ -80,8 +88,10 @@ ${devDependencies.map((String dep) => ' $dep: $constraint').join('\n')} /// Adds a 'dependency_overrides:' section with entries for each package in /// [overrides] to [package]. void addDependencyOverridesSection( - RepositoryPackage package, Iterable overrides, - {String path = '../'}) { + RepositoryPackage package, + Iterable overrides, { + String path = '../', + }) { final String originalContent = package.pubspecFile.readAsStringSync(); package.pubspecFile.writeAsStringSync(''' $originalContent @@ -93,63 +103,79 @@ ${overrides.map((String dep) => ' $dep:\n path: $path').join('\n')} Map getDependencyOverrides(RepositoryPackage package) { final Pubspec pubspec = package.parsePubspec(); - return pubspec.dependencyOverrides.map((String name, Dependency dep) => - MapEntry( - name, (dep is PathDependency) ? dep.path : dep.toString())); + return pubspec.dependencyOverrides.map( + (String name, Dependency dep) => MapEntry( + name, + (dep is PathDependency) ? dep.path : dep.toString(), + ), + ); } test('no-ops for no plugins', () async { createFakePackage('foo', packagesDir, isFlutter: true); - final RepositoryPackage packageBar = - createFakePackage('bar', packagesDir, isFlutter: true); + final RepositoryPackage packageBar = createFakePackage( + 'bar', + packagesDir, + isFlutter: true, + ); addDependencies(packageBar, ['foo']); - final String originalPubspecContents = - packageBar.pubspecFile.readAsStringSync(); + final String originalPubspecContents = packageBar.pubspecFile + .readAsStringSync(); - final List output = - await runCapturingPrint(runner, ['make-deps-path-based']); + final List output = await runCapturingPrint(runner, [ + 'make-deps-path-based', + ]); expect( output, - containsAllInOrder([ - contains('No target dependencies'), - ]), + containsAllInOrder([contains('No target dependencies')]), ); // The 'foo' reference should not have been modified. expect(packageBar.pubspecFile.readAsStringSync(), originalPubspecContents); }); test('includes explanatory comment', () async { - final RepositoryPackage packageA = - createFakePackage('package_a', packagesDir, isFlutter: true); + final RepositoryPackage packageA = createFakePackage( + 'package_a', + packagesDir, + isFlutter: true, + ); createFakePackage('package_b', packagesDir, isFlutter: true); - addDependencies(packageA, [ - 'package_b', - ]); + addDependencies(packageA, ['package_b']); - await runCapturingPrint(runner, - ['make-deps-path-based', '--target-dependencies=package_b']); + await runCapturingPrint(runner, [ + 'make-deps-path-based', + '--target-dependencies=package_b', + ]); expect( - packageA.pubspecFile.readAsLinesSync(), - containsAllInOrder([ - '# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.', - '# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins', - 'dependency_overrides:', - ])); + packageA.pubspecFile.readAsLinesSync(), + containsAllInOrder([ + '# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.', + '# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins', + 'dependency_overrides:', + ]), + ); }); test('rewrites "dependencies" references', () async { - final RepositoryPackage simplePackage = - createFakePackage('foo', packagesDir, isFlutter: true); + final RepositoryPackage simplePackage = createFakePackage( + 'foo', + packagesDir, + isFlutter: true, + ); final Directory pluginGroup = packagesDir.childDirectory('bar'); createFakePackage('bar_platform_interface', pluginGroup, isFlutter: true); - final RepositoryPackage pluginImplementation = - createFakePlugin('bar_android', pluginGroup); - final RepositoryPackage pluginAppFacing = - createFakePlugin('bar', pluginGroup); + final RepositoryPackage pluginImplementation = createFakePlugin( + 'bar_android', + pluginGroup, + ); + final RepositoryPackage pluginAppFacing = createFakePlugin( + 'bar', + pluginGroup, + ); addDependencies(simplePackage, [ 'bar', @@ -160,63 +186,73 @@ ${overrides.map((String dep) => ' $dep:\n path: $path').join('\n')} 'bar_platform_interface', 'bar_android', ]); - addDependencies(pluginImplementation, [ - 'bar_platform_interface', - ]); + addDependencies(pluginImplementation, ['bar_platform_interface']); final List output = await runCapturingPrint(runner, [ 'make-deps-path-based', - '--target-dependencies=bar,bar_platform_interface' + '--target-dependencies=bar,bar_platform_interface', ]); expect( - output, - containsAll([ - 'Rewriting references to: bar, bar_platform_interface...', - ' Modified packages/bar/bar/pubspec.yaml', - ' Modified packages/bar/bar_android/pubspec.yaml', - ' Modified packages/foo/pubspec.yaml', - ])); + output, + containsAll([ + 'Rewriting references to: bar, bar_platform_interface...', + ' Modified packages/bar/bar/pubspec.yaml', + ' Modified packages/bar/bar_android/pubspec.yaml', + ' Modified packages/foo/pubspec.yaml', + ]), + ); expect( - output, - isNot(contains( - ' Modified packages/bar/bar_platform_interface/pubspec.yaml'))); + output, + isNot( + contains(' Modified packages/bar/bar_platform_interface/pubspec.yaml'), + ), + ); - final Map simplePackageOverrides = - getDependencyOverrides(simplePackage); + final Map simplePackageOverrides = getDependencyOverrides( + simplePackage, + ); expect(simplePackageOverrides.length, 2); expect(simplePackageOverrides['bar'], '../../packages/bar/bar'); - expect(simplePackageOverrides['bar_platform_interface'], - '../../packages/bar/bar_platform_interface'); + expect( + simplePackageOverrides['bar_platform_interface'], + '../../packages/bar/bar_platform_interface', + ); final Map appFacingPackageOverrides = getDependencyOverrides(pluginAppFacing); expect(appFacingPackageOverrides.length, 1); - expect(appFacingPackageOverrides['bar_platform_interface'], - '../../../packages/bar/bar_platform_interface'); + expect( + appFacingPackageOverrides['bar_platform_interface'], + '../../../packages/bar/bar_platform_interface', + ); }); test('rewrites "dev_dependencies" references', () async { createFakePackage('foo', packagesDir); - final RepositoryPackage builderPackage = - createFakePackage('foo_builder', packagesDir); + final RepositoryPackage builderPackage = createFakePackage( + 'foo_builder', + packagesDir, + ); - addDevDependenciesSection(builderPackage, [ - 'foo', - ]); + addDevDependenciesSection(builderPackage, ['foo']); - final List output = await runCapturingPrint( - runner, ['make-deps-path-based', '--target-dependencies=foo']); + final List output = await runCapturingPrint(runner, [ + 'make-deps-path-based', + '--target-dependencies=foo', + ]); expect( - output, - containsAll([ - 'Rewriting references to: foo...', - ' Modified packages/foo_builder/pubspec.yaml', - ])); + output, + containsAll([ + 'Rewriting references to: foo...', + ' Modified packages/foo_builder/pubspec.yaml', + ]), + ); - final Map overrides = - getDependencyOverrides(builderPackage); + final Map overrides = getDependencyOverrides( + builderPackage, + ); expect(overrides.length, 1); expect(overrides['foo'], '../../packages/foo'); }); @@ -224,167 +260,219 @@ ${overrides.map((String dep) => ' $dep:\n path: $path').join('\n')} test('rewrites examples when rewriting the main package', () async { final Directory pluginGroup = packagesDir.childDirectory('bar'); createFakePackage('bar_platform_interface', pluginGroup, isFlutter: true); - final RepositoryPackage pluginImplementation = - createFakePlugin('bar_android', pluginGroup); - final RepositoryPackage pluginAppFacing = - createFakePlugin('bar', pluginGroup); + final RepositoryPackage pluginImplementation = createFakePlugin( + 'bar_android', + pluginGroup, + ); + final RepositoryPackage pluginAppFacing = createFakePlugin( + 'bar', + pluginGroup, + ); addDependencies(pluginAppFacing, [ 'bar_platform_interface', 'bar_android', ]); - addDependencies(pluginImplementation, [ - 'bar_platform_interface', - ]); + addDependencies(pluginImplementation, ['bar_platform_interface']); - await runCapturingPrint(runner, - ['make-deps-path-based', '--target-dependencies=bar_android']); + await runCapturingPrint(runner, [ + 'make-deps-path-based', + '--target-dependencies=bar_android', + ]); - final Map exampleOverrides = - getDependencyOverrides(pluginAppFacing.getExamples().first); + final Map exampleOverrides = getDependencyOverrides( + pluginAppFacing.getExamples().first, + ); expect(exampleOverrides.length, 1); - expect(exampleOverrides['bar_android'], - '../../../../packages/bar/bar_android'); + expect( + exampleOverrides['bar_android'], + '../../../../packages/bar/bar_android', + ); }); - test('example overrides include both local and main-package dependencies', - () async { - final Directory pluginGroup = packagesDir.childDirectory('bar'); - createFakePackage('bar_platform_interface', pluginGroup, isFlutter: true); - createFakePlugin('bar_android', pluginGroup); - final RepositoryPackage pluginAppFacing = - createFakePlugin('bar', pluginGroup); - createFakePackage('another_package', packagesDir); + test( + 'example overrides include both local and main-package dependencies', + () async { + final Directory pluginGroup = packagesDir.childDirectory('bar'); + createFakePackage('bar_platform_interface', pluginGroup, isFlutter: true); + createFakePlugin('bar_android', pluginGroup); + final RepositoryPackage pluginAppFacing = createFakePlugin( + 'bar', + pluginGroup, + ); + createFakePackage('another_package', packagesDir); - addDependencies(pluginAppFacing, [ - 'bar_platform_interface', - 'bar_android', - ]); - addDependencies(pluginAppFacing.getExamples().first, [ - 'another_package', - ]); + addDependencies(pluginAppFacing, [ + 'bar_platform_interface', + 'bar_android', + ]); + addDependencies(pluginAppFacing.getExamples().first, [ + 'another_package', + ]); - await runCapturingPrint(runner, [ - 'make-deps-path-based', - '--target-dependencies=bar_android,another_package' - ]); + await runCapturingPrint(runner, [ + 'make-deps-path-based', + '--target-dependencies=bar_android,another_package', + ]); - final Map exampleOverrides = - getDependencyOverrides(pluginAppFacing.getExamples().first); - expect(exampleOverrides.length, 2); - expect(exampleOverrides['another_package'], - '../../../../packages/another_package'); - expect(exampleOverrides['bar_android'], - '../../../../packages/bar/bar_android'); - }); + final Map exampleOverrides = getDependencyOverrides( + pluginAppFacing.getExamples().first, + ); + expect(exampleOverrides.length, 2); + expect( + exampleOverrides['another_package'], + '../../../../packages/another_package', + ); + expect( + exampleOverrides['bar_android'], + '../../../../packages/bar/bar_android', + ); + }, + ); - test('does not rewrite path-based dependencies that are already path based', - () async { - final RepositoryPackage package = createFakePlugin('foo', packagesDir); - final RepositoryPackage example = package.getExamples().first; - addPathDependencies(example, ['foo'], relativePathBase: '../'); + test( + 'does not rewrite path-based dependencies that are already path based', + () async { + final RepositoryPackage package = createFakePlugin('foo', packagesDir); + final RepositoryPackage example = package.getExamples().first; + addPathDependencies(example, ['foo'], relativePathBase: '../'); - await runCapturingPrint( - runner, ['make-deps-path-based', '--target-dependencies=foo']); + await runCapturingPrint(runner, [ + 'make-deps-path-based', + '--target-dependencies=foo', + ]); - final Map exampleOverrides = - getDependencyOverrides(example); - expect(exampleOverrides.length, 0); - }); + final Map exampleOverrides = getDependencyOverrides( + example, + ); + expect(exampleOverrides.length, 0); + }, + ); test( - 'alphabetizes overrides from different sections to avoid lint warnings in analysis', - () async { - createFakePackage('a', packagesDir); - createFakePackage('b', packagesDir); - createFakePackage('c', packagesDir); - final RepositoryPackage targetPackage = - createFakePackage('target', packagesDir); + 'alphabetizes overrides from different sections to avoid lint warnings in analysis', + () async { + createFakePackage('a', packagesDir); + createFakePackage('b', packagesDir); + createFakePackage('c', packagesDir); + final RepositoryPackage targetPackage = createFakePackage( + 'target', + packagesDir, + ); - addDependencies(targetPackage, ['a', 'c']); - addDevDependenciesSection(targetPackage, ['b']); + addDependencies(targetPackage, ['a', 'c']); + addDevDependenciesSection(targetPackage, ['b']); - final List output = await runCapturingPrint(runner, - ['make-deps-path-based', '--target-dependencies=c,a,b']); + final List output = await runCapturingPrint(runner, [ + 'make-deps-path-based', + '--target-dependencies=c,a,b', + ]); - expect( + expect( output, containsAllInOrder([ 'Rewriting references to: c, a, b...', ' Modified packages/target/pubspec.yaml', - ])); + ]), + ); - // This matches with a regex in order to all for either flow style or - // expanded style output. - expect( + // This matches with a regex in order to all for either flow style or + // expanded style output. + expect( targetPackage.pubspecFile.readAsStringSync(), - matches(RegExp(r'dependency_overrides:.*a:.*b:.*c:.*', - multiLine: true, dotAll: true))); - }); + matches( + RegExp( + r'dependency_overrides:.*a:.*b:.*c:.*', + multiLine: true, + dotAll: true, + ), + ), + ); + }, + ); test('finds third_party packages', () async { createFakePackage('bar', thirdPartyPackagesDir, isFlutter: true); - final RepositoryPackage firstPartyPackge = - createFakePlugin('foo', packagesDir); + final RepositoryPackage firstPartyPackge = createFakePlugin( + 'foo', + packagesDir, + ); - addDependencies(firstPartyPackge, [ - 'bar', - ]); + addDependencies(firstPartyPackge, ['bar']); - final List output = await runCapturingPrint( - runner, ['make-deps-path-based', '--target-dependencies=bar']); + final List output = await runCapturingPrint(runner, [ + 'make-deps-path-based', + '--target-dependencies=bar', + ]); expect( - output, - containsAll([ - 'Rewriting references to: bar...', - ' Modified packages/foo/pubspec.yaml', - ])); + output, + containsAll([ + 'Rewriting references to: bar...', + ' Modified packages/foo/pubspec.yaml', + ]), + ); - final Map simplePackageOverrides = - getDependencyOverrides(firstPartyPackge); + final Map simplePackageOverrides = getDependencyOverrides( + firstPartyPackge, + ); expect(simplePackageOverrides.length, 1); expect(simplePackageOverrides['bar'], '../../third_party/packages/bar'); }); - test('handles third_party target package references in third_party', - () async { - createFakePackage('bar', thirdPartyPackagesDir, isFlutter: true); - final RepositoryPackage otherThirdPartyPackge = - createFakePlugin('foo', thirdPartyPackagesDir); + test( + 'handles third_party target package references in third_party', + () async { + createFakePackage('bar', thirdPartyPackagesDir, isFlutter: true); + final RepositoryPackage otherThirdPartyPackge = createFakePlugin( + 'foo', + thirdPartyPackagesDir, + ); - addDependencies(otherThirdPartyPackge, [ - 'bar', - ]); + addDependencies(otherThirdPartyPackge, ['bar']); - final List output = await runCapturingPrint( - runner, ['make-deps-path-based', '--target-dependencies=bar']); + final List output = await runCapturingPrint(runner, [ + 'make-deps-path-based', + '--target-dependencies=bar', + ]); - expect( + expect( output, containsAll([ 'Rewriting references to: bar...', ' Modified third_party/packages/foo/pubspec.yaml', - ])); + ]), + ); - final Map simplePackageOverrides = - getDependencyOverrides(otherThirdPartyPackge); - expect(simplePackageOverrides.length, 1); - expect(simplePackageOverrides['bar'], '../../../third_party/packages/bar'); - }); + final Map simplePackageOverrides = + getDependencyOverrides(otherThirdPartyPackge); + expect(simplePackageOverrides.length, 1); + expect( + simplePackageOverrides['bar'], + '../../../third_party/packages/bar', + ); + }, + ); // This test case ensures that running CI using this command on an interim // PR that itself used this command won't fail on the rewrite step. test('running a second time no-ops without failing', () async { - final RepositoryPackage simplePackage = - createFakePackage('foo', packagesDir, isFlutter: true); + final RepositoryPackage simplePackage = createFakePackage( + 'foo', + packagesDir, + isFlutter: true, + ); final Directory pluginGroup = packagesDir.childDirectory('bar'); createFakePackage('bar_platform_interface', pluginGroup, isFlutter: true); - final RepositoryPackage pluginImplementation = - createFakePlugin('bar_android', pluginGroup); - final RepositoryPackage pluginAppFacing = - createFakePlugin('bar', pluginGroup); + final RepositoryPackage pluginImplementation = createFakePlugin( + 'bar_android', + pluginGroup, + ); + final RepositoryPackage pluginAppFacing = createFakePlugin( + 'bar', + pluginGroup, + ); addDependencies(simplePackage, [ 'bar', @@ -395,51 +483,64 @@ ${overrides.map((String dep) => ' $dep:\n path: $path').join('\n')} 'bar_platform_interface', 'bar_android', ]); - addDependencies(pluginImplementation, [ - 'bar_platform_interface', - ]); + addDependencies(pluginImplementation, ['bar_platform_interface']); await runCapturingPrint(runner, [ 'make-deps-path-based', - '--target-dependencies=bar,bar_platform_interface' + '--target-dependencies=bar,bar_platform_interface', ]); - final String simplePackageUpdatedContent = - simplePackage.pubspecFile.readAsStringSync(); - final String appFacingPackageUpdatedContent = - pluginAppFacing.pubspecFile.readAsStringSync(); - final String implementationPackageUpdatedContent = - pluginImplementation.pubspecFile.readAsStringSync(); + final String simplePackageUpdatedContent = simplePackage.pubspecFile + .readAsStringSync(); + final String appFacingPackageUpdatedContent = pluginAppFacing.pubspecFile + .readAsStringSync(); + final String implementationPackageUpdatedContent = pluginImplementation + .pubspecFile + .readAsStringSync(); final List output = await runCapturingPrint(runner, [ 'make-deps-path-based', - '--target-dependencies=bar,bar_platform_interface' + '--target-dependencies=bar,bar_platform_interface', ]); expect( - output, - containsAll([ - 'Rewriting references to: bar, bar_platform_interface...', - ' Modified packages/bar/bar/pubspec.yaml', - ' Modified packages/bar/bar_android/pubspec.yaml', - ' Modified packages/foo/pubspec.yaml', - ])); - expect(simplePackage.pubspecFile.readAsStringSync(), - simplePackageUpdatedContent); - expect(pluginAppFacing.pubspecFile.readAsStringSync(), - appFacingPackageUpdatedContent); - expect(pluginImplementation.pubspecFile.readAsStringSync(), - implementationPackageUpdatedContent); + output, + containsAll([ + 'Rewriting references to: bar, bar_platform_interface...', + ' Modified packages/bar/bar/pubspec.yaml', + ' Modified packages/bar/bar_android/pubspec.yaml', + ' Modified packages/foo/pubspec.yaml', + ]), + ); + expect( + simplePackage.pubspecFile.readAsStringSync(), + simplePackageUpdatedContent, + ); + expect( + pluginAppFacing.pubspecFile.readAsStringSync(), + appFacingPackageUpdatedContent, + ); + expect( + pluginImplementation.pubspecFile.readAsStringSync(), + implementationPackageUpdatedContent, + ); }); test('sorts with existing overrides', () async { - final RepositoryPackage simplePackage = - createFakePackage('foo', packagesDir, isFlutter: true); + final RepositoryPackage simplePackage = createFakePackage( + 'foo', + packagesDir, + isFlutter: true, + ); final Directory pluginGroup = packagesDir.childDirectory('bar'); createFakePackage('bar_platform_interface', pluginGroup, isFlutter: true); - final RepositoryPackage pluginImplementation = - createFakePlugin('bar_android', pluginGroup); - final RepositoryPackage pluginAppFacing = - createFakePlugin('bar', pluginGroup); + final RepositoryPackage pluginImplementation = createFakePlugin( + 'bar_android', + pluginGroup, + ); + final RepositoryPackage pluginAppFacing = createFakePlugin( + 'bar', + pluginGroup, + ); addDependencies(simplePackage, [ 'bar', @@ -450,29 +551,26 @@ ${overrides.map((String dep) => ' $dep:\n path: $path').join('\n')} 'bar_platform_interface', 'bar_android', ]); - addDependencies(pluginImplementation, [ - 'bar_platform_interface', - ]); - addDependencyOverridesSection( - simplePackage, - ['bar_android'], - path: '../bar/bar_android', - ); + addDependencies(pluginImplementation, ['bar_platform_interface']); + addDependencyOverridesSection(simplePackage, [ + 'bar_android', + ], path: '../bar/bar_android'); await runCapturingPrint(runner, [ 'make-deps-path-based', - '--target-dependencies=bar,bar_platform_interface' + '--target-dependencies=bar,bar_platform_interface', ]); - final String simplePackageUpdatedContent = - simplePackage.pubspecFile.readAsStringSync(); + final String simplePackageUpdatedContent = simplePackage.pubspecFile + .readAsStringSync(); expect( - simplePackageUpdatedContent.split('\n'), - containsAllInOrder([ - contains(' bar:'), - contains(' bar_android:'), - contains(' bar_platform_interface:'), - ])); + simplePackageUpdatedContent.split('\n'), + containsAllInOrder([ + contains(' bar:'), + contains(' bar_android:'), + contains(' bar_platform_interface:'), + ]), + ); }); group('target-dependencies-with-non-breaking-updates', () { @@ -484,25 +582,24 @@ ${overrides.map((String dep) => ' $dep:\n path: $path').join('\n')} ].map((File file) => file.path).join('\n'); gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: changedFileOutput)), - ]; + FakeProcessInfo(MockProcess(stdout: changedFileOutput)), + ]; // Simulate no change to the version in the interface's pubspec.yaml. gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo( - MockProcess(stdout: package.pubspecFile.readAsStringSync())), - ]; + FakeProcessInfo( + MockProcess(stdout: package.pubspecFile.readAsStringSync()), + ), + ]; final List output = await runCapturingPrint(runner, [ 'make-deps-path-based', - '--target-dependencies-with-non-breaking-updates' + '--target-dependencies-with-non-breaking-updates', ]); expect( output, - containsAllInOrder([ - contains('No target dependencies'), - ]), + containsAllInOrder([contains('No target dependencies')]), ); }); @@ -513,12 +610,12 @@ ${overrides.map((String dep) => ' $dep:\n path: $path').join('\n')} ].map((File file) => file.path).join('\n'); gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: changedFileOutput)), - ]; + FakeProcessInfo(MockProcess(stdout: changedFileOutput)), + ]; final List output = await runCapturingPrint(runner, [ 'make-deps-path-based', - '--target-dependencies-with-non-breaking-updates' + '--target-dependencies-with-non-breaking-updates', ]); expect( @@ -531,9 +628,12 @@ ${overrides.map((String dep) => ' $dep:\n path: $path').join('\n')} }); test('includes bugfix version changes as targets', () async { - const String newVersion = '1.0.1'; - final RepositoryPackage package = - createFakePackage('foo', packagesDir, version: newVersion); + const newVersion = '1.0.1'; + final RepositoryPackage package = createFakePackage( + 'foo', + packagesDir, + version: newVersion, + ); final File pubspecFile = package.pubspecFile; final String changedFileOutput = [ @@ -541,19 +641,20 @@ ${overrides.map((String dep) => ' $dep:\n path: $path').join('\n')} ].map((File file) => file.path).join('\n'); gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: changedFileOutput)), - ]; - final String gitPubspecContents = - pubspecFile.readAsStringSync().replaceAll(newVersion, '1.0.0'); + FakeProcessInfo(MockProcess(stdout: changedFileOutput)), + ]; + final String gitPubspecContents = pubspecFile + .readAsStringSync() + .replaceAll(newVersion, '1.0.0'); // Simulate no change to the version in the interface's pubspec.yaml. gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: gitPubspecContents)), - ]; + FakeProcessInfo(MockProcess(stdout: gitPubspecContents)), + ]; final List output = await runCapturingPrint(runner, [ 'make-deps-path-based', - '--target-dependencies-with-non-breaking-updates' + '--target-dependencies-with-non-breaking-updates', ]); expect( @@ -565,9 +666,12 @@ ${overrides.map((String dep) => ' $dep:\n path: $path').join('\n')} }); test('includes minor version changes to 1.0+ as targets', () async { - const String newVersion = '1.1.0'; - final RepositoryPackage package = - createFakePackage('foo', packagesDir, version: newVersion); + const newVersion = '1.1.0'; + final RepositoryPackage package = createFakePackage( + 'foo', + packagesDir, + version: newVersion, + ); final File pubspecFile = package.pubspecFile; final String changedFileOutput = [ @@ -575,19 +679,20 @@ ${overrides.map((String dep) => ' $dep:\n path: $path').join('\n')} ].map((File file) => file.path).join('\n'); gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: changedFileOutput)), - ]; - final String gitPubspecContents = - pubspecFile.readAsStringSync().replaceAll(newVersion, '1.0.0'); + FakeProcessInfo(MockProcess(stdout: changedFileOutput)), + ]; + final String gitPubspecContents = pubspecFile + .readAsStringSync() + .replaceAll(newVersion, '1.0.0'); // Simulate no change to the version in the interface's pubspec.yaml. gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: gitPubspecContents)), - ]; + FakeProcessInfo(MockProcess(stdout: gitPubspecContents)), + ]; final List output = await runCapturingPrint(runner, [ 'make-deps-path-based', - '--target-dependencies-with-non-breaking-updates' + '--target-dependencies-with-non-breaking-updates', ]); expect( @@ -599,9 +704,12 @@ ${overrides.map((String dep) => ' $dep:\n path: $path').join('\n')} }); test('does not include major version changes as targets', () async { - const String newVersion = '2.0.0'; - final RepositoryPackage package = - createFakePackage('foo', packagesDir, version: newVersion); + const newVersion = '2.0.0'; + final RepositoryPackage package = createFakePackage( + 'foo', + packagesDir, + version: newVersion, + ); final File pubspecFile = package.pubspecFile; final String changedFileOutput = [ @@ -609,33 +717,35 @@ ${overrides.map((String dep) => ' $dep:\n path: $path').join('\n')} ].map((File file) => file.path).join('\n'); gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: changedFileOutput)), - ]; - final String gitPubspecContents = - pubspecFile.readAsStringSync().replaceAll(newVersion, '1.0.0'); + FakeProcessInfo(MockProcess(stdout: changedFileOutput)), + ]; + final String gitPubspecContents = pubspecFile + .readAsStringSync() + .replaceAll(newVersion, '1.0.0'); // Simulate no change to the version in the interface's pubspec.yaml. gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: gitPubspecContents)), - ]; + FakeProcessInfo(MockProcess(stdout: gitPubspecContents)), + ]; final List output = await runCapturingPrint(runner, [ 'make-deps-path-based', - '--target-dependencies-with-non-breaking-updates' + '--target-dependencies-with-non-breaking-updates', ]); expect( output, - containsAllInOrder([ - contains('No target dependencies'), - ]), + containsAllInOrder([contains('No target dependencies')]), ); }); test('does not include minor version changes to 0.x as targets', () async { - const String newVersion = '0.8.0'; - final RepositoryPackage package = - createFakePackage('foo', packagesDir, version: newVersion); + const newVersion = '0.8.0'; + final RepositoryPackage package = createFakePackage( + 'foo', + packagesDir, + version: newVersion, + ); final File pubspecFile = package.pubspecFile; final String changedFileOutput = [ @@ -643,39 +753,44 @@ ${overrides.map((String dep) => ' $dep:\n path: $path').join('\n')} ].map((File file) => file.path).join('\n'); gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: changedFileOutput)), - ]; - final String gitPubspecContents = - pubspecFile.readAsStringSync().replaceAll(newVersion, '0.7.0'); + FakeProcessInfo(MockProcess(stdout: changedFileOutput)), + ]; + final String gitPubspecContents = pubspecFile + .readAsStringSync() + .replaceAll(newVersion, '0.7.0'); // Simulate no change to the version in the interface's pubspec.yaml. gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: gitPubspecContents)), - ]; + FakeProcessInfo(MockProcess(stdout: gitPubspecContents)), + ]; final List output = await runCapturingPrint(runner, [ 'make-deps-path-based', - '--target-dependencies-with-non-breaking-updates' + '--target-dependencies-with-non-breaking-updates', ]); expect( output, - containsAllInOrder([ - contains('No target dependencies'), - ]), + containsAllInOrder([contains('No target dependencies')]), ); }); test('does not update references with an older major version', () async { - const String newVersion = '2.0.1'; - final RepositoryPackage targetPackage = - createFakePackage('foo', packagesDir, version: newVersion); - final RepositoryPackage referencingPackage = - createFakePackage('bar', packagesDir); + const newVersion = '2.0.1'; + final RepositoryPackage targetPackage = createFakePackage( + 'foo', + packagesDir, + version: newVersion, + ); + final RepositoryPackage referencingPackage = createFakePackage( + 'bar', + packagesDir, + ); // For a dependency on ^1.0.0, the 2.0.0->2.0.1 update should not apply. - addDependencies(referencingPackage, ['foo'], - constraint: '^1.0.0'); + addDependencies(referencingPackage, [ + 'foo', + ], constraint: '^1.0.0'); final File pubspecFile = targetPackage.pubspecFile; final String changedFileOutput = [ @@ -683,41 +798,46 @@ ${overrides.map((String dep) => ' $dep:\n path: $path').join('\n')} ].map((File file) => file.path).join('\n'); gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: changedFileOutput)), - ]; - final String gitPubspecContents = - pubspecFile.readAsStringSync().replaceAll(newVersion, '2.0.0'); + FakeProcessInfo(MockProcess(stdout: changedFileOutput)), + ]; + final String gitPubspecContents = pubspecFile + .readAsStringSync() + .replaceAll(newVersion, '2.0.0'); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: gitPubspecContents)), - ]; + FakeProcessInfo(MockProcess(stdout: gitPubspecContents)), + ]; final List output = await runCapturingPrint(runner, [ 'make-deps-path-based', - '--target-dependencies-with-non-breaking-updates' + '--target-dependencies-with-non-breaking-updates', ]); final Pubspec referencingPubspec = referencingPackage.parsePubspec(); expect( output, - containsAllInOrder([ - contains('Rewriting references to: foo'), - ]), + containsAllInOrder([contains('Rewriting references to: foo')]), ); expect(referencingPubspec.dependencyOverrides.isEmpty, true); }); test('does update references with a matching version range', () async { - const String newVersion = '2.0.1'; - final RepositoryPackage targetPackage = - createFakePackage('foo', packagesDir, version: newVersion); - final RepositoryPackage referencingPackage = - createFakePackage('bar', packagesDir); + const newVersion = '2.0.1'; + final RepositoryPackage targetPackage = createFakePackage( + 'foo', + packagesDir, + version: newVersion, + ); + final RepositoryPackage referencingPackage = createFakePackage( + 'bar', + packagesDir, + ); // For a dependency on ^1.0.0, the 2.0.0->2.0.1 update should not apply. - addDependencies(referencingPackage, ['foo'], - constraint: '^2.0.0'); + addDependencies(referencingPackage, [ + 'foo', + ], constraint: '^2.0.0'); final File pubspecFile = targetPackage.pubspecFile; final String changedFileOutput = [ @@ -725,38 +845,41 @@ ${overrides.map((String dep) => ' $dep:\n path: $path').join('\n')} ].map((File file) => file.path).join('\n'); gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: changedFileOutput)), - ]; - final String gitPubspecContents = - pubspecFile.readAsStringSync().replaceAll(newVersion, '2.0.0'); + FakeProcessInfo(MockProcess(stdout: changedFileOutput)), + ]; + final String gitPubspecContents = pubspecFile + .readAsStringSync() + .replaceAll(newVersion, '2.0.0'); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: gitPubspecContents)), - ]; + FakeProcessInfo(MockProcess(stdout: gitPubspecContents)), + ]; final List output = await runCapturingPrint(runner, [ 'make-deps-path-based', - '--target-dependencies-with-non-breaking-updates' + '--target-dependencies-with-non-breaking-updates', ]); final Pubspec referencingPubspec = referencingPackage.parsePubspec(); expect( output, - containsAllInOrder([ - contains('Rewriting references to: foo'), - ]), + containsAllInOrder([contains('Rewriting references to: foo')]), + ); + expect( + referencingPubspec.dependencyOverrides['foo'] is PathDependency, + true, ); - expect(referencingPubspec.dependencyOverrides['foo'] is PathDependency, - true); }); test('skips anything outside of the packages directory', () async { final Directory toolDir = packagesDir.parent.childDirectory('tool'); - const String newVersion = '1.1.0'; + const newVersion = '1.1.0'; final RepositoryPackage package = createFakePackage( - 'flutter_plugin_tools', toolDir, - version: newVersion); + 'flutter_plugin_tools', + toolDir, + version: newVersion, + ); // Simulate a minor version change so it would be a target. final File pubspecFile = package.pubspecFile; @@ -765,25 +888,27 @@ ${overrides.map((String dep) => ' $dep:\n path: $path').join('\n')} ].map((File file) => file.path).join('\n'); gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: changedFileOutput)), - ]; - final String gitPubspecContents = - pubspecFile.readAsStringSync().replaceAll(newVersion, '1.0.0'); + FakeProcessInfo(MockProcess(stdout: changedFileOutput)), + ]; + final String gitPubspecContents = pubspecFile + .readAsStringSync() + .replaceAll(newVersion, '1.0.0'); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: gitPubspecContents)), - ]; + FakeProcessInfo(MockProcess(stdout: gitPubspecContents)), + ]; final List output = await runCapturingPrint(runner, [ 'make-deps-path-based', - '--target-dependencies-with-non-breaking-updates' + '--target-dependencies-with-non-breaking-updates', ]); expect( output, containsAllInOrder([ contains( - 'Skipping /tool/flutter_plugin_tools/pubspec.yaml; not in packages directory.'), + 'Skipping /tool/flutter_plugin_tools/pubspec.yaml; not in packages directory.', + ), contains('No target dependencies'), ]), ); diff --git a/script/tool/test/mocks.dart b/script/tool/test/mocks.dart index 7d6395278a54..bd32df846dbe 100644 --- a/script/tool/test/mocks.dart +++ b/script/tool/test/mocks.dart @@ -109,12 +109,12 @@ MockGitDir createForwardingMockGitDir({ required Directory packagesDir, required ProcessRunner processRunner, }) { - final MockGitDir gitDir = MockGitDir(); + final gitDir = MockGitDir(); when(gitDir.path).thenReturn(packagesDir.parent.path); - when(gitDir.runCommand(any, throwOnError: anyNamed('throwOnError'))) - .thenAnswer((Invocation invocation) { - final List arguments = - invocation.positionalArguments[0]! as List; + when( + gitDir.runCommand(any, throwOnError: anyNamed('throwOnError')), + ).thenAnswer((Invocation invocation) { + final arguments = invocation.positionalArguments[0]! as List; final String gitCommand = arguments.removeAt(0); return processRunner.run('git-$gitCommand', arguments); }); diff --git a/script/tool/test/native_test_command_test.dart b/script/tool/test/native_test_command_test.dart index 19b4b88bb75e..6c51ed7f2fd1 100644 --- a/script/tool/test/native_test_command_test.dart +++ b/script/tool/test/native_test_command_test.dart @@ -40,7 +40,7 @@ final Map _kDeviceListMap = { 'identifier': 'com.apple.CoreSimulator.SimRuntime.iOS-13-4', 'version': '13.4', 'isAvailable': true, - 'name': 'iOS 13.4' + 'name': 'iOS 13.4', }, ], 'devices': { @@ -55,10 +55,10 @@ final Map _kDeviceListMap = { 'deviceTypeIdentifier': 'com.apple.CoreSimulator.SimDeviceType.iPhone-8-Plus', 'state': 'Shutdown', - 'name': 'iPhone 8 Plus' - } - ] - } + 'name': 'iPhone 8 Plus', + }, + ], + }, }; const String _fakeCmakeCommand = 'path/to/cmake'; @@ -66,9 +66,16 @@ const String _archDirX64 = 'x64'; const String _archDirArm64 = 'arm64'; void _createFakeCMakeCache( - RepositoryPackage plugin, Platform platform, String? archDir) { - final CMakeProject project = CMakeProject(getExampleDir(plugin), - platform: platform, buildMode: 'Release', arch: archDir); + RepositoryPackage plugin, + Platform platform, + String? archDir, +) { + final project = CMakeProject( + getExampleDir(plugin), + platform: platform, + buildMode: 'Release', + arch: archDir, + ); final File cache = project.buildDirectory.childFile('CMakeCache.txt'); cache.createSync(recursive: true); cache.writeAsStringSync('CMAKE_COMMAND:INTERNAL=$_fakeCmakeCommand'); @@ -77,7 +84,7 @@ void _createFakeCMakeCache( // TODO(stuartmorgan): Rework these tests to use a mock Xcode instead of // doing all the process mocking and validation. void main() { - const String kDestination = '--ios-destination'; + const kDestination = '--ios-destination'; group('test native_test_command on Posix', () { late MockPlatform mockPlatform; @@ -94,7 +101,7 @@ void main() { final GitDir gitDir; (:packagesDir, :processRunner, :gitProcessRunner, :gitDir) = configureBaseCommandMocks(platform: mockPlatform); - final NativeTestCommand command = NativeTestCommand( + final command = NativeTestCommand( packagesDir, processRunner: processRunner, platform: mockPlatform, @@ -102,53 +109,51 @@ void main() { ); runner = CommandRunner( - 'native_test_command', 'Test for native_test_command'); + 'native_test_command', + 'Test for native_test_command', + ); runner.addCommand(command); }); // Returns a FakeProcessInfo to provide for "xcrun xcodebuild -list" for a // project that contains [targets]. FakeProcessInfo getMockXcodebuildListProcess(List targets) { - final Map projects = { - 'project': { - 'targets': targets, - } + final projects = { + 'project': {'targets': targets}, }; - return FakeProcessInfo(MockProcess(stdout: jsonEncode(projects)), - ['xcodebuild', '-list']); + return FakeProcessInfo( + MockProcess(stdout: jsonEncode(projects)), + ['xcodebuild', '-list'], + ); } // Returns the ProcessCall to expect for checking the targets present in // the [package]'s [platform]/Runner.xcodeproj. ProcessCall getTargetCheckCall(Directory package, String platform) { - return ProcessCall( - 'xcrun', - [ - 'xcodebuild', - '-list', - '-json', - '-project', - package - .childDirectory(platform) - .childDirectory('Runner.xcodeproj') - .path, - ], - null); + return ProcessCall('xcrun', [ + 'xcodebuild', + '-list', + '-json', + '-project', + package + .childDirectory(platform) + .childDirectory('Runner.xcodeproj') + .path, + ], null); } // Returns the ProcessCall to expect for generating the native project files // with a --config-only build on iOS or macOS. ProcessCall getConfigOnlyDarwinBuildCall( - Directory package, FlutterPlatform platform) { - return ProcessCall( - 'flutter', - [ - 'build', - if (platform == FlutterPlatform.ios) 'ios' else 'macos', - '--debug', - '--config-only', - ], - package.path); + Directory package, + FlutterPlatform platform, + ) { + return ProcessCall('flutter', [ + 'build', + if (platform == FlutterPlatform.ios) 'ios' else 'macos', + '--debug', + '--config-only', + ], package.path); } // Returns the ProcessCall to expect for running the tests in the @@ -160,50 +165,47 @@ void main() { List extraFlags = const [], bool treatWarningsAsErrors = true, }) { - return ProcessCall( - 'xcrun', - [ - 'xcodebuild', - 'clean', - 'test', - '-workspace', - '$platform/Runner.xcworkspace', - '-scheme', - 'Runner', - '-configuration', - 'Debug', - if (destination != null) ...['-destination', destination], - ...extraFlags, - if (treatWarningsAsErrors) 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', - ], - package.path); + return ProcessCall('xcrun', [ + 'xcodebuild', + 'clean', + 'test', + '-workspace', + '$platform/Runner.xcworkspace', + '-scheme', + 'Runner', + '-configuration', + 'Debug', + if (destination != null) ...['-destination', destination], + ...extraFlags, + if (treatWarningsAsErrors) 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', + ], package.path); } // Returns the ProcessCall to expect for build the Linux unit tests for the // given plugin. ProcessCall getLinuxBuildCall(RepositoryPackage plugin) { - return ProcessCall( - 'cmake', - [ - '--build', - getExampleDir(plugin) - .childDirectory('build') - .childDirectory('linux') - .childDirectory('x64') - .childDirectory('release') - .path, - '--target', - 'unit_tests' - ], - null); + return ProcessCall('cmake', [ + '--build', + getExampleDir(plugin) + .childDirectory('build') + .childDirectory('linux') + .childDirectory('x64') + .childDirectory('release') + .path, + '--target', + 'unit_tests', + ], null); } test('fails if no platforms are provided', () async { Error? commandError; final List output = await runCapturingPrint( - runner, ['native-test'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['native-test'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -216,14 +218,13 @@ void main() { test('fails if all test types are disabled', () async { Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'native-test', - '--macos', - '--no-unit', - '--no-integration', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['native-test', '--macos', '--no-unit', '--no-integration'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -235,86 +236,123 @@ void main() { }); test('reports skips with no tests', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); processRunner.mockProcessesForExecutable['xcrun'] = [ getMockXcodebuildListProcess(['RunnerTests', 'RunnerUITests']), // Exit code 66 from testing indicates no tests. - FakeProcessInfo( - MockProcess(exitCode: 66), ['xcodebuild', 'clean', 'test']), + FakeProcessInfo(MockProcess(exitCode: 66), [ + 'xcodebuild', + 'clean', + 'test', + ]), ]; - final List output = await runCapturingPrint( - runner, ['native-test', '--macos', '--no-unit']); + final List output = await runCapturingPrint(runner, [ + 'native-test', + '--macos', + '--no-unit', + ]); expect( - output, - containsAllInOrder([ - contains('No tests found.'), - contains('Skipped 1 package(s)'), - ])); + output, + containsAllInOrder([ + contains('No tests found.'), + contains('Skipped 1 package(s)'), + ]), + ); expect( - processRunner.recordedCalls, - orderedEquals([ - getTargetCheckCall(pluginExampleDirectory, 'macos'), - getConfigOnlyDarwinBuildCall( - pluginExampleDirectory, FlutterPlatform.macos), - getRunTestCall(pluginExampleDirectory, 'macos', - extraFlags: ['-only-testing:RunnerUITests']), - ])); + processRunner.recordedCalls, + orderedEquals([ + getTargetCheckCall(pluginExampleDirectory, 'macos'), + getConfigOnlyDarwinBuildCall( + pluginExampleDirectory, + FlutterPlatform.macos, + ), + getRunTestCall( + pluginExampleDirectory, + 'macos', + extraFlags: ['-only-testing:RunnerUITests'], + ), + ]), + ); }); group('iOS', () { test('skip if iOS is not supported', () async { - createFakePlugin('plugin', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); - final List output = await runCapturingPrint(runner, - ['native-test', '--ios', kDestination, 'foo_destination']); + final List output = await runCapturingPrint(runner, [ + 'native-test', + '--ios', + kDestination, + 'foo_destination', + ]); expect( - output, - containsAllInOrder([ - contains('No implementation for iOS.'), - contains('SKIPPING: Nothing to test for target platform(s).'), - ])); + output, + containsAllInOrder([ + contains('No implementation for iOS.'), + contains('SKIPPING: Nothing to test for target platform(s).'), + ]), + ); expect(processRunner.recordedCalls, orderedEquals([])); }); test('skip if iOS is implemented in a federated package', () async { - createFakePlugin('plugin', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.federated) - }); + createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.federated), + }, + ); - final List output = await runCapturingPrint(runner, - ['native-test', '--ios', kDestination, 'foo_destination']); + final List output = await runCapturingPrint(runner, [ + 'native-test', + '--ios', + kDestination, + 'foo_destination', + ]); expect( - output, - containsAllInOrder([ - contains('No implementation for iOS.'), - contains('SKIPPING: Nothing to test for target platform(s).'), - ])); + output, + containsAllInOrder([ + contains('No implementation for iOS.'), + contains('SKIPPING: Nothing to test for target platform(s).'), + ]), + ); expect(processRunner.recordedCalls, orderedEquals([])); }); test('running with correct destination', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline) - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); processRunner.mockProcessesForExecutable['xcrun'] = [ - getMockXcodebuildListProcess( - ['RunnerTests', 'RunnerUITests']), + getMockXcodebuildListProcess([ + 'RunnerTests', + 'RunnerUITests', + ]), ]; final List output = await runCapturingPrint(runner, [ @@ -325,64 +363,83 @@ void main() { ]); expect( - output, - containsAllInOrder([ - contains('Running for plugin'), - contains('Successfully ran iOS xctest for plugin/example') - ])); + output, + containsAllInOrder([ + contains('Running for plugin'), + contains('Successfully ran iOS xctest for plugin/example'), + ]), + ); expect( - processRunner.recordedCalls, - orderedEquals([ - getTargetCheckCall(pluginExampleDirectory, 'ios'), - getConfigOnlyDarwinBuildCall( - pluginExampleDirectory, FlutterPlatform.ios), - getRunTestCall(pluginExampleDirectory, 'ios', - destination: 'foo_destination'), - ])); + processRunner.recordedCalls, + orderedEquals([ + getTargetCheckCall(pluginExampleDirectory, 'ios'), + getConfigOnlyDarwinBuildCall( + pluginExampleDirectory, + FlutterPlatform.ios, + ), + getRunTestCall( + pluginExampleDirectory, + 'ios', + destination: 'foo_destination', + ), + ]), + ); }); - test('Not specifying --ios-destination assigns an available simulator', - () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, + test( + 'Not specifying --ios-destination assigns an available simulator', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline) - }); - final Directory pluginExampleDirectory = getExampleDir(plugin); - - processRunner.mockProcessesForExecutable['xcrun'] = [ - FakeProcessInfo(MockProcess(stdout: jsonEncode(_kDeviceListMap)), - ['simctl', 'list']), - getMockXcodebuildListProcess( - ['RunnerTests', 'RunnerUITests']), - ]; + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); + final Directory pluginExampleDirectory = getExampleDir(plugin); + + processRunner.mockProcessesForExecutable['xcrun'] = [ + FakeProcessInfo( + MockProcess(stdout: jsonEncode(_kDeviceListMap)), + ['simctl', 'list'], + ), + getMockXcodebuildListProcess([ + 'RunnerTests', + 'RunnerUITests', + ]), + ]; - await runCapturingPrint(runner, ['native-test', '--ios']); + await runCapturingPrint(runner, ['native-test', '--ios']); - expect( + expect( processRunner.recordedCalls, orderedEquals([ - const ProcessCall( - 'xcrun', - [ - 'simctl', - 'list', - 'devices', - 'runtimes', - 'available', - '--json', - ], - null), + const ProcessCall('xcrun', [ + 'simctl', + 'list', + 'devices', + 'runtimes', + 'available', + '--json', + ], null), getTargetCheckCall(pluginExampleDirectory, 'ios'), getConfigOnlyDarwinBuildCall( - pluginExampleDirectory, FlutterPlatform.ios), - getRunTestCall(pluginExampleDirectory, 'ios', - destination: 'id=$_simulatorDeviceId'), - ])); - }); + pluginExampleDirectory, + FlutterPlatform.ios, + ), + getRunTestCall( + pluginExampleDirectory, + 'ios', + destination: 'id=$_simulatorDeviceId', + ), + ]), + ); + }, + ); group('file filtering', () { - const List files = [ + const files = [ 'pubspec.yaml', 'foo.dart', 'foo.java', @@ -393,16 +450,21 @@ void main() { 'foo.cpp', 'foo.h', ]; - for (final String file in files) { + for (final file in files) { test('runs command for changes to $file', () async { createFakePackage('package_a', packagesDir); gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: + ''' packages/package_a/$file -''')), - ]; +''', + ), + ), + ]; // The target platform is irrelevant here; because this repo's // packages are fully federated, there's no need to distinguish @@ -410,13 +472,14 @@ packages/package_a/$file // Kotlin files change), because package-level filering will already // accomplish the same goal. final List output = await runCapturingPrint( - runner, ['native-test', '--android']); + runner, + ['native-test', '--android'], + ); expect( - output, - containsAllInOrder([ - contains('Running for package_a'), - ])); + output, + containsAllInOrder([contains('Running for package_a')]), + ); }); } @@ -425,26 +488,32 @@ packages/package_a/$file gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' README.md CODEOWNERS packages/package_a/CHANGELOG.md -''')), - ]; +''', + ), + ), + ]; - final List output = await runCapturingPrint( - runner, ['native-test', 'android']); + final List output = await runCapturingPrint(runner, [ + 'native-test', + 'android', + ]); expect( - output, - isNot(containsAllInOrder([ - contains('Running for package_a'), - ]))); + output, + isNot( + containsAllInOrder([contains('Running for package_a')]), + ), + ); expect( - output, - containsAllInOrder([ - contains('SKIPPING ALL PACKAGES'), - ])); + output, + containsAllInOrder([contains('SKIPPING ALL PACKAGES')]), + ); }); }); }); @@ -453,47 +522,61 @@ packages/package_a/CHANGELOG.md test('skip if macOS is not supported', () async { createFakePlugin('plugin', packagesDir); - final List output = - await runCapturingPrint(runner, ['native-test', '--macos']); + final List output = await runCapturingPrint(runner, [ + 'native-test', + '--macos', + ]); expect( - output, - containsAllInOrder([ - contains('No implementation for macOS.'), - contains('SKIPPING: Nothing to test for target platform(s).'), - ])); + output, + containsAllInOrder([ + contains('No implementation for macOS.'), + contains('SKIPPING: Nothing to test for target platform(s).'), + ]), + ); expect(processRunner.recordedCalls, orderedEquals([])); }); test('skip if macOS is implemented in a federated package', () async { - createFakePlugin('plugin', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.federated), - }); + createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.federated), + }, + ); - final List output = - await runCapturingPrint(runner, ['native-test', '--macos']); + final List output = await runCapturingPrint(runner, [ + 'native-test', + '--macos', + ]); expect( - output, - containsAllInOrder([ - contains('No implementation for macOS.'), - contains('SKIPPING: Nothing to test for target platform(s).'), - ])); + output, + containsAllInOrder([ + contains('No implementation for macOS.'), + contains('SKIPPING: Nothing to test for target platform(s).'), + ]), + ); expect(processRunner.recordedCalls, orderedEquals([])); }); test('runs for macOS plugin', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); processRunner.mockProcessesForExecutable['xcrun'] = [ - getMockXcodebuildListProcess( - ['RunnerTests', 'RunnerUITests']), + getMockXcodebuildListProcess([ + 'RunnerTests', + 'RunnerUITests', + ]), ]; final List output = await runCapturingPrint(runner, [ @@ -502,18 +585,23 @@ packages/package_a/CHANGELOG.md ]); expect( - output, - contains( - contains('Successfully ran macOS xctest for plugin/example'))); + output, + contains( + contains('Successfully ran macOS xctest for plugin/example'), + ), + ); expect( - processRunner.recordedCalls, - orderedEquals([ - getTargetCheckCall(pluginExampleDirectory, 'macos'), - getConfigOnlyDarwinBuildCall( - pluginExampleDirectory, FlutterPlatform.macos), - getRunTestCall(pluginExampleDirectory, 'macos'), - ])); + processRunner.recordedCalls, + orderedEquals([ + getTargetCheckCall(pluginExampleDirectory, 'macos'), + getConfigOnlyDarwinBuildCall( + pluginExampleDirectory, + FlutterPlatform.macos, + ), + getRunTestCall(pluginExampleDirectory, 'macos'), + ]), + ); }); }); @@ -523,7 +611,7 @@ packages/package_a/CHANGELOG.md 'plugin', packagesDir, platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) + platformAndroid: const PlatformDetails(PlatformSupport.inline), }, extraFiles: [ 'example/android/gradlew', @@ -541,14 +629,10 @@ packages/package_a/CHANGELOG.md expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - androidFolder.childFile('gradlew').path, - const [ - 'app:testDebugUnitTest', - 'plugin:testDebugUnitTest', - ], - androidFolder.path, - ), + ProcessCall(androidFolder.childFile('gradlew').path, const [ + 'app:testDebugUnitTest', + 'plugin:testDebugUnitTest', + ], androidFolder.path), ]), ); }); @@ -558,7 +642,7 @@ packages/package_a/CHANGELOG.md 'plugin', packagesDir, platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) + platformAndroid: const PlatformDetails(PlatformSupport.inline), }, extraFiles: [ 'example/android/gradlew', @@ -576,14 +660,10 @@ packages/package_a/CHANGELOG.md expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - androidFolder.childFile('gradlew').path, - const [ - 'app:testDebugUnitTest', - 'plugin:testDebugUnitTest', - ], - androidFolder.path, - ), + ProcessCall(androidFolder.childFile('gradlew').path, const [ + 'app:testDebugUnitTest', + 'plugin:testDebugUnitTest', + ], androidFolder.path), ]), ); }); @@ -593,7 +673,7 @@ packages/package_a/CHANGELOG.md 'plugin', packagesDir, platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) + platformAndroid: const PlatformDetails(PlatformSupport.inline), }, examples: ['example1', 'example2'], extraFiles: [ @@ -607,10 +687,12 @@ packages/package_a/CHANGELOG.md await runCapturingPrint(runner, ['native-test', '--android']); final List examples = plugin.getExamples().toList(); - final Directory androidFolder1 = - examples[0].platformDirectory(FlutterPlatform.android); - final Directory androidFolder2 = - examples[1].platformDirectory(FlutterPlatform.android); + final Directory androidFolder1 = examples[0].platformDirectory( + FlutterPlatform.android, + ); + final Directory androidFolder2 = examples[1].platformDirectory( + FlutterPlatform.android, + ); expect( processRunner.recordedCalls, @@ -625,9 +707,7 @@ packages/package_a/CHANGELOG.md ), ProcessCall( androidFolder2.childFile('gradlew').path, - const [ - 'app:testDebugUnitTest', - ], + const ['app:testDebugUnitTest'], androidFolder2.path, ), ]), @@ -639,7 +719,7 @@ packages/package_a/CHANGELOG.md 'plugin', packagesDir, platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) + platformAndroid: const PlatformDetails(PlatformSupport.inline), }, extraFiles: [ 'example/android/gradlew', @@ -647,8 +727,11 @@ packages/package_a/CHANGELOG.md ], ); - await runCapturingPrint( - runner, ['native-test', '--android', '--no-unit']); + await runCapturingPrint(runner, [ + 'native-test', + '--android', + '--no-unit', + ]); final Directory androidFolder = plugin .getExamples() @@ -658,42 +741,39 @@ packages/package_a/CHANGELOG.md expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - androidFolder.childFile('gradlew').path, - const [ - 'app:connectedAndroidTest', - _androidIntegrationTestFilter, - _allAbiFlag, - ], - androidFolder.path, - ), + ProcessCall(androidFolder.childFile('gradlew').path, const [ + 'app:connectedAndroidTest', + _androidIntegrationTestFilter, + _allAbiFlag, + ], androidFolder.path), ]), ); }); test( - 'ignores Java integration test files using (or defining) DartIntegrationTest', - () async { - const String dartTestDriverRelativePath = - 'android/app/src/androidTest/java/io/flutter/plugins/plugin/FlutterActivityTest.java'; - final RepositoryPackage plugin = createFakePlugin( - 'plugin', - packagesDir, - platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) - }, - extraFiles: [ - 'example/android/gradlew', - 'example/android/app/src/androidTest/java/io/flutter/plugins/DartIntegrationTest.java', - 'example/android/app/src/androidTest/java/io/flutter/plugins/DartIntegrationTest.kt', - 'example/$dartTestDriverRelativePath', - ], - ); - - final File dartTestDriverFile = childFileWithSubcomponents( + 'ignores Java integration test files using (or defining) DartIntegrationTest', + () async { + const dartTestDriverRelativePath = + 'android/app/src/androidTest/java/io/flutter/plugins/plugin/FlutterActivityTest.java'; + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + }, + extraFiles: [ + 'example/android/gradlew', + 'example/android/app/src/androidTest/java/io/flutter/plugins/DartIntegrationTest.java', + 'example/android/app/src/androidTest/java/io/flutter/plugins/DartIntegrationTest.kt', + 'example/$dartTestDriverRelativePath', + ], + ); + + final File dartTestDriverFile = childFileWithSubcomponents( plugin.getExamples().first.directory, - p.posix.split(dartTestDriverRelativePath)); - dartTestDriverFile.writeAsStringSync(''' + p.posix.split(dartTestDriverRelativePath), + ); + dartTestDriverFile.writeAsStringSync(''' import io.flutter.plugins.DartIntegrationTest; import org.junit.runner.RunWith; @@ -703,38 +783,40 @@ public class FlutterActivityTest { } '''); - await runCapturingPrint( - runner, ['native-test', '--android', '--no-unit']); + await runCapturingPrint(runner, [ + 'native-test', + '--android', + '--no-unit', + ]); - // Nothing should run since those files are all - // integration_test-specific. - expect( - processRunner.recordedCalls, - orderedEquals([]), - ); - }); + // Nothing should run since those files are all + // integration_test-specific. + expect(processRunner.recordedCalls, orderedEquals([])); + }, + ); test( - 'fails for Java integration tests Using FlutterTestRunner without @DartIntegrationTest', - () async { - const String dartTestDriverRelativePath = - 'android/app/src/androidTest/java/io/flutter/plugins/plugin/FlutterActivityTest.java'; - final RepositoryPackage plugin = createFakePlugin( - 'plugin', - packagesDir, - platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) - }, - extraFiles: [ - 'example/android/gradlew', - 'example/$dartTestDriverRelativePath', - ], - ); - - final File dartTestDriverFile = childFileWithSubcomponents( + 'fails for Java integration tests Using FlutterTestRunner without @DartIntegrationTest', + () async { + const dartTestDriverRelativePath = + 'android/app/src/androidTest/java/io/flutter/plugins/plugin/FlutterActivityTest.java'; + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + }, + extraFiles: [ + 'example/android/gradlew', + 'example/$dartTestDriverRelativePath', + ], + ); + + final File dartTestDriverFile = childFileWithSubcomponents( plugin.getExamples().first.directory, - p.posix.split(dartTestDriverRelativePath)); - dartTestDriverFile.writeAsStringSync(''' + p.posix.split(dartTestDriverRelativePath), + ); + dartTestDriverFile.writeAsStringSync(''' import io.flutter.plugins.DartIntegrationTest; import org.junit.runner.RunWith; @@ -743,30 +825,39 @@ public class FlutterActivityTest { } '''); - Error? commandError; - final List output = await runCapturingPrint( - runner, ['native-test', '--android', '--no-unit'], + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['native-test', '--android', '--no-unit'], errorHandler: (Error e) { - commandError = e; - }); + commandError = e; + }, + ); - expect(commandError, isA()); - expect( + expect(commandError, isA()); + expect( output, contains( - contains(misconfiguredJavaIntegrationTestErrorExplanation))); - expect( + contains(misconfiguredJavaIntegrationTestErrorExplanation), + ), + ); + expect( output, - contains(contains( - 'example/android/app/src/androidTest/java/io/flutter/plugins/plugin/FlutterActivityTest.java'))); - }); + contains( + contains( + 'example/android/app/src/androidTest/java/io/flutter/plugins/plugin/FlutterActivityTest.java', + ), + ), + ); + }, + ); test('runs all tests when present', () async { final RepositoryPackage plugin = createFakePlugin( 'plugin', packagesDir, platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) + platformAndroid: const PlatformDetails(PlatformSupport.inline), }, extraFiles: [ 'android/src/test/example_test.java', @@ -785,23 +876,15 @@ public class FlutterActivityTest { expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - androidFolder.childFile('gradlew').path, - const [ - 'app:testDebugUnitTest', - 'plugin:testDebugUnitTest', - ], - androidFolder.path, - ), - ProcessCall( - androidFolder.childFile('gradlew').path, - const [ - 'app:connectedAndroidTest', - _androidIntegrationTestFilter, - _allAbiFlag, - ], - androidFolder.path, - ), + ProcessCall(androidFolder.childFile('gradlew').path, const [ + 'app:testDebugUnitTest', + 'plugin:testDebugUnitTest', + ], androidFolder.path), + ProcessCall(androidFolder.childFile('gradlew').path, const [ + 'app:connectedAndroidTest', + _androidIntegrationTestFilter, + _allAbiFlag, + ], androidFolder.path), ]), ); }); @@ -811,7 +894,7 @@ public class FlutterActivityTest { 'plugin', packagesDir, platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) + platformAndroid: const PlatformDetails(PlatformSupport.inline), }, extraFiles: [ 'android/src/test/example_test.java', @@ -820,8 +903,11 @@ public class FlutterActivityTest { ], ); - await runCapturingPrint( - runner, ['native-test', '--android', '--no-unit']); + await runCapturingPrint(runner, [ + 'native-test', + '--android', + '--no-unit', + ]); final Directory androidFolder = plugin .getExamples() @@ -831,15 +917,11 @@ public class FlutterActivityTest { expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - androidFolder.childFile('gradlew').path, - const [ - 'app:connectedAndroidTest', - _androidIntegrationTestFilter, - _allAbiFlag, - ], - androidFolder.path, - ), + ProcessCall(androidFolder.childFile('gradlew').path, const [ + 'app:connectedAndroidTest', + _androidIntegrationTestFilter, + _allAbiFlag, + ], androidFolder.path), ]), ); }); @@ -849,7 +931,7 @@ public class FlutterActivityTest { 'plugin', packagesDir, platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) + platformAndroid: const PlatformDetails(PlatformSupport.inline), }, extraFiles: [ 'android/src/test/example_test.java', @@ -858,8 +940,11 @@ public class FlutterActivityTest { ], ); - await runCapturingPrint( - runner, ['native-test', '--android', '--no-integration']); + await runCapturingPrint(runner, [ + 'native-test', + '--android', + '--no-integration', + ]); final Directory androidFolder = plugin .getExamples() @@ -869,14 +954,10 @@ public class FlutterActivityTest { expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - androidFolder.childFile('gradlew').path, - const [ - 'app:testDebugUnitTest', - 'plugin:testDebugUnitTest', - ], - androidFolder.path, - ), + ProcessCall(androidFolder.childFile('gradlew').path, const [ + 'app:testDebugUnitTest', + 'plugin:testDebugUnitTest', + ], androidFolder.path), ]), ); }); @@ -886,34 +967,31 @@ public class FlutterActivityTest { 'plugin', packagesDir, platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) + platformAndroid: const PlatformDetails(PlatformSupport.inline), }, extraFiles: [ 'example/android/app/src/test/example_test.java', ], ); final RepositoryPackage example = package.getExamples().first; - final Directory androidFolder = - example.platformDirectory(FlutterPlatform.android); + final Directory androidFolder = example.platformDirectory( + FlutterPlatform.android, + ); await runCapturingPrint(runner, ['native-test', '--android']); expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - getFlutterCommand(mockPlatform), - const ['build', 'apk', '--config-only'], - example.path, - ), - ProcessCall( - androidFolder.childFile('gradlew').path, - const [ - 'app:testDebugUnitTest', - 'plugin:testDebugUnitTest', - ], - androidFolder.path, - ), + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'build', + 'apk', + '--config-only', + ], example.path), + ProcessCall(androidFolder.childFile('gradlew').path, const [ + 'app:testDebugUnitTest', + 'plugin:testDebugUnitTest', + ], androidFolder.path), ]), ); }); @@ -923,23 +1001,27 @@ public class FlutterActivityTest { 'plugin', packagesDir, platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) + platformAndroid: const PlatformDetails(PlatformSupport.inline), }, extraFiles: [ 'example/android/app/src/test/example_test.java', ], ); - processRunner - .mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = - [FakeProcessInfo(MockProcess(exitCode: 1))]; + processRunner.mockProcessesForExecutable[getFlutterCommand( + mockPlatform, + )] = [ + FakeProcessInfo(MockProcess(exitCode: 1)), + ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['native-test', '--android'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['native-test', '--android'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); @@ -957,7 +1039,7 @@ public class FlutterActivityTest { 'plugin1', packagesDir, platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) + platformAndroid: const PlatformDetails(PlatformSupport.inline), }, extraFiles: [ 'example/android/gradlew', @@ -969,7 +1051,7 @@ public class FlutterActivityTest { 'plugin2', packagesDir, platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) + platformAndroid: const PlatformDetails(PlatformSupport.inline), }, extraFiles: [ 'android/src/test/example_test.java', @@ -978,21 +1060,23 @@ public class FlutterActivityTest { ); final List output = await runCapturingPrint( - runner, ['native-test', '--android'], - errorHandler: (Error e) { - // Having no unit tests is fatal, but that's not the point of this - // test so just ignore the failure. - }); + runner, + ['native-test', '--android'], + errorHandler: (Error e) { + // Having no unit tests is fatal, but that's not the point of this + // test so just ignore the failure. + }, + ); expect( - output, - containsAllInOrder([ - contains('No Android unit tests found for plugin1/example'), - contains('Running integration tests...'), - contains( - 'No Android integration tests found for plugin2/example'), - contains('Running unit tests...'), - ])); + output, + containsAllInOrder([ + contains('No Android unit tests found for plugin1/example'), + contains('Running integration tests...'), + contains('No Android integration tests found for plugin2/example'), + contains('Running unit tests...'), + ]), + ); }); test('fails when a unit test fails', () async { @@ -1000,7 +1084,7 @@ public class FlutterActivityTest { 'plugin', packagesDir, platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) + platformAndroid: const PlatformDetails(PlatformSupport.inline), }, extraFiles: [ 'example/android/gradlew', @@ -1019,10 +1103,12 @@ public class FlutterActivityTest { Error? commandError; final List output = await runCapturingPrint( - runner, ['native-test', '--android'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['native-test', '--android'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); @@ -1031,7 +1117,7 @@ public class FlutterActivityTest { containsAllInOrder([ contains('plugin/example unit tests failed.'), contains('The following packages had errors:'), - contains('plugin') + contains('plugin'), ]), ); }); @@ -1041,7 +1127,7 @@ public class FlutterActivityTest { 'plugin', packagesDir, platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) + platformAndroid: const PlatformDetails(PlatformSupport.inline), }, extraFiles: [ 'example/android/gradlew', @@ -1058,18 +1144,22 @@ public class FlutterActivityTest { .path; processRunner.mockProcessesForExecutable[gradlewPath] = [ - FakeProcessInfo( - MockProcess(), ['app:testDebugUnitTest']), // unit passes - FakeProcessInfo(MockProcess(exitCode: 1), - ['app:connectedAndroidTest']), // integration fails - ]; + FakeProcessInfo(MockProcess(), [ + 'app:testDebugUnitTest', + ]), // unit passes + FakeProcessInfo(MockProcess(exitCode: 1), [ + 'app:connectedAndroidTest', + ]), // integration fails + ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['native-test', '--android'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['native-test', '--android'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); @@ -1078,7 +1168,7 @@ public class FlutterActivityTest { containsAllInOrder([ contains('plugin/example integration tests failed.'), contains('The following packages had errors:'), - contains('plugin') + contains('plugin'), ]), ); }); @@ -1088,7 +1178,7 @@ public class FlutterActivityTest { 'plugin', packagesDir, platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) + platformAndroid: const PlatformDetails(PlatformSupport.inline), }, extraFiles: [ 'example/android/gradlew', @@ -1098,10 +1188,12 @@ public class FlutterActivityTest { Error? commandError; final List output = await runCapturingPrint( - runner, ['native-test', '--android'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['native-test', '--android'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); @@ -1110,22 +1202,24 @@ public class FlutterActivityTest { containsAllInOrder([ contains('No Android unit tests found for plugin/example'), contains( - 'No unit tests ran. Plugins are required to have unit tests.'), + 'No unit tests ran. Plugins are required to have unit tests.', + ), contains('The following packages had errors:'), - contains('plugin:\n' - ' No unit tests ran (use --exclude if this is intentional).') + contains( + 'plugin:\n' + ' No unit tests ran (use --exclude if this is intentional).', + ), ]), ); }); test('skips if Android is not supported', () async { - createFakePlugin( - 'plugin', - packagesDir, - ); + createFakePlugin('plugin', packagesDir); - final List output = await runCapturingPrint( - runner, ['native-test', '--android']); + final List output = await runCapturingPrint(runner, [ + 'native-test', + '--android', + ]); expect( output, @@ -1141,12 +1235,15 @@ public class FlutterActivityTest { 'plugin', packagesDir, platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline) + platformAndroid: const PlatformDetails(PlatformSupport.inline), }, ); - final List output = await runCapturingPrint( - runner, ['native-test', '--android', '--no-unit']); + final List output = await runCapturingPrint(runner, [ + 'native-test', + '--android', + '--no-unit', + ]); expect( output, @@ -1160,18 +1257,22 @@ public class FlutterActivityTest { group('Linux', () { test('builds and runs unit tests', () async { - const String testBinaryRelativePath = + const testBinaryRelativePath = 'build/linux/x64/release/bar/plugin_test'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/$testBinaryRelativePath' - ], platformSupport: { - platformLinux: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: ['example/$testBinaryRelativePath'], + platformSupport: { + platformLinux: const PlatformDetails(PlatformSupport.inline), + }, + ); _createFakeCMakeCache(plugin, mockPlatform, _archDirX64); - final File testBinary = childFileWithSubcomponents(plugin.directory, - ['example', ...testBinaryRelativePath.split('/')]); + final File testBinary = childFileWithSubcomponents( + plugin.directory, + ['example', ...testBinaryRelativePath.split('/')], + ); final List output = await runCapturingPrint(runner, [ 'native-test', @@ -1188,30 +1289,36 @@ public class FlutterActivityTest { ); expect( - processRunner.recordedCalls, - orderedEquals([ - getLinuxBuildCall(plugin), - ProcessCall(testBinary.path, const [], null), - ])); + processRunner.recordedCalls, + orderedEquals([ + getLinuxBuildCall(plugin), + ProcessCall(testBinary.path, const [], null), + ]), + ); }); test('only runs release unit tests', () async { - const String debugTestBinaryRelativePath = + const debugTestBinaryRelativePath = 'build/linux/x64/debug/bar/plugin_test'; - const String releaseTestBinaryRelativePath = + const releaseTestBinaryRelativePath = 'build/linux/x64/release/bar/plugin_test'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/$debugTestBinaryRelativePath', - 'example/$releaseTestBinaryRelativePath' - ], platformSupport: { - platformLinux: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'example/$debugTestBinaryRelativePath', + 'example/$releaseTestBinaryRelativePath', + ], + platformSupport: { + platformLinux: const PlatformDetails(PlatformSupport.inline), + }, + ); _createFakeCMakeCache(plugin, mockPlatform, _archDirX64); final File releaseTestBinary = childFileWithSubcomponents( - plugin.directory, - ['example', ...releaseTestBinaryRelativePath.split('/')]); + plugin.directory, + ['example', ...releaseTestBinaryRelativePath.split('/')], + ); final List output = await runCapturingPrint(runner, [ 'native-test', @@ -1228,34 +1335,40 @@ public class FlutterActivityTest { ); expect( - processRunner.recordedCalls, - orderedEquals([ - getLinuxBuildCall(plugin), - ProcessCall(releaseTestBinary.path, const [], null), - ])); + processRunner.recordedCalls, + orderedEquals([ + getLinuxBuildCall(plugin), + ProcessCall(releaseTestBinary.path, const [], null), + ]), + ); }); test('fails if CMake has not been configured', () async { - createFakePlugin('plugin', packagesDir, - platformSupport: { - platformLinux: const PlatformDetails(PlatformSupport.inline), - }); + createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformLinux: const PlatformDetails(PlatformSupport.inline), + }, + ); Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'native-test', - '--linux', - '--no-integration', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['native-test', '--linux', '--no-integration'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ - contains('plugin:\n' - ' Examples must be built before testing.') + contains( + 'plugin:\n' + ' Examples must be built before testing.', + ), ]), ); @@ -1263,99 +1376,105 @@ public class FlutterActivityTest { }); test('fails if there are no unit tests', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformLinux: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformLinux: const PlatformDetails(PlatformSupport.inline), + }, + ); _createFakeCMakeCache(plugin, mockPlatform, _archDirX64); Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'native-test', - '--linux', - '--no-integration', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['native-test', '--linux', '--no-integration'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, - containsAllInOrder([ - contains('No test binaries found.'), - ]), + containsAllInOrder([contains('No test binaries found.')]), ); expect( - processRunner.recordedCalls, - orderedEquals([ - getLinuxBuildCall(plugin), - ])); + processRunner.recordedCalls, + orderedEquals([getLinuxBuildCall(plugin)]), + ); }); test('fails if a unit test fails', () async { - const String testBinaryRelativePath = + const testBinaryRelativePath = 'build/linux/x64/release/bar/plugin_test'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/$testBinaryRelativePath' - ], platformSupport: { - platformLinux: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: ['example/$testBinaryRelativePath'], + platformSupport: { + platformLinux: const PlatformDetails(PlatformSupport.inline), + }, + ); _createFakeCMakeCache(plugin, mockPlatform, _archDirX64); - final File testBinary = childFileWithSubcomponents(plugin.directory, - ['example', ...testBinaryRelativePath.split('/')]); + final File testBinary = childFileWithSubcomponents( + plugin.directory, + ['example', ...testBinaryRelativePath.split('/')], + ); processRunner.mockProcessesForExecutable[testBinary.path] = - [ - FakeProcessInfo(MockProcess(exitCode: 1)), - ]; + [FakeProcessInfo(MockProcess(exitCode: 1))]; Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'native-test', - '--linux', - '--no-integration', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['native-test', '--linux', '--no-integration'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, - containsAllInOrder([ - contains('Running plugin_test...'), - ]), + containsAllInOrder([contains('Running plugin_test...')]), ); expect( - processRunner.recordedCalls, - orderedEquals([ - getLinuxBuildCall(plugin), - ProcessCall(testBinary.path, const [], null), - ])); + processRunner.recordedCalls, + orderedEquals([ + getLinuxBuildCall(plugin), + ProcessCall(testBinary.path, const [], null), + ]), + ); }); }); // Tests behaviors of implementation that is shared between iOS and macOS. group('iOS or macOS', () { test('fails if xcrun fails', () async { - createFakePlugin('plugin', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); processRunner.mockProcessesForExecutable['xcrun'] = [ - FakeProcessInfo(MockProcess(exitCode: 1)) + FakeProcessInfo(MockProcess(exitCode: 1)), ]; Error? commandError; - final List output = - await runCapturingPrint(runner, ['native-test', '--macos'], - errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['native-test', '--macos'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -1368,16 +1487,21 @@ public class FlutterActivityTest { }); test('honors unit-only', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); processRunner.mockProcessesForExecutable['xcrun'] = [ - getMockXcodebuildListProcess( - ['RunnerTests', 'RunnerUITests']), + getMockXcodebuildListProcess([ + 'RunnerTests', + 'RunnerUITests', + ]), ]; final List output = await runCapturingPrint(runner, [ @@ -1387,34 +1511,46 @@ public class FlutterActivityTest { ]); expect( - output, - contains( - contains('Successfully ran macOS xctest for plugin/example'))); + output, + contains( + contains('Successfully ran macOS xctest for plugin/example'), + ), + ); // --no-integration should translate to '-only-testing:RunnerTests'. expect( - processRunner.recordedCalls, - orderedEquals([ - getTargetCheckCall(pluginExampleDirectory, 'macos'), - getConfigOnlyDarwinBuildCall( - pluginExampleDirectory, FlutterPlatform.macos), - getRunTestCall(pluginExampleDirectory, 'macos', - extraFlags: ['-only-testing:RunnerTests']), - ])); + processRunner.recordedCalls, + orderedEquals([ + getTargetCheckCall(pluginExampleDirectory, 'macos'), + getConfigOnlyDarwinBuildCall( + pluginExampleDirectory, + FlutterPlatform.macos, + ), + getRunTestCall( + pluginExampleDirectory, + 'macos', + extraFlags: ['-only-testing:RunnerTests'], + ), + ]), + ); }); test('honors integration-only', () async { final RepositoryPackage plugin1 = createFakePlugin( - 'plugin', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + 'plugin', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin1); processRunner.mockProcessesForExecutable['xcrun'] = [ - getMockXcodebuildListProcess( - ['RunnerTests', 'RunnerUITests']), + getMockXcodebuildListProcess([ + 'RunnerTests', + 'RunnerUITests', + ]), ]; final List output = await runCapturingPrint(runner, [ @@ -1424,28 +1560,38 @@ public class FlutterActivityTest { ]); expect( - output, - contains( - contains('Successfully ran macOS xctest for plugin/example'))); + output, + contains( + contains('Successfully ran macOS xctest for plugin/example'), + ), + ); // --no-unit should translate to '-only-testing:RunnerUITests'. expect( - processRunner.recordedCalls, - orderedEquals([ - getTargetCheckCall(pluginExampleDirectory, 'macos'), - getConfigOnlyDarwinBuildCall( - pluginExampleDirectory, FlutterPlatform.macos), - getRunTestCall(pluginExampleDirectory, 'macos', - extraFlags: ['-only-testing:RunnerUITests']), - ])); + processRunner.recordedCalls, + orderedEquals([ + getTargetCheckCall(pluginExampleDirectory, 'macos'), + getConfigOnlyDarwinBuildCall( + pluginExampleDirectory, + FlutterPlatform.macos, + ), + getRunTestCall( + pluginExampleDirectory, + 'macos', + extraFlags: ['-only-testing:RunnerUITests'], + ), + ]), + ); }); test('skips when the requested target is not present', () async { final RepositoryPackage plugin1 = createFakePlugin( - 'plugin', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + 'plugin', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin1); @@ -1462,25 +1608,28 @@ public class FlutterActivityTest { ]); expect( - output, - containsAllInOrder([ - contains( - 'No "RunnerUITests" target in plugin/example; skipping.'), - ])); + output, + containsAllInOrder([ + contains('No "RunnerUITests" target in plugin/example; skipping.'), + ]), + ); expect( - processRunner.recordedCalls, - orderedEquals([ - getTargetCheckCall(pluginExampleDirectory, 'macos'), - ])); + processRunner.recordedCalls, + orderedEquals([ + getTargetCheckCall(pluginExampleDirectory, 'macos'), + ]), + ); }); test('fails if there are no unit tests', () async { final RepositoryPackage plugin1 = createFakePlugin( - 'plugin', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + 'plugin', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin1); @@ -1489,53 +1638,64 @@ public class FlutterActivityTest { ]; Error? commandError; - final List output = - await runCapturingPrint(runner, ['native-test', '--macos'], - errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['native-test', '--macos'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('No "RunnerTests" target in plugin/example; skipping.'), - contains( - 'No unit tests ran. Plugins are required to have unit tests.'), - contains('The following packages had errors:'), - contains('plugin:\n' - ' No unit tests ran (use --exclude if this is intentional).'), - ])); + output, + containsAllInOrder([ + contains('No "RunnerTests" target in plugin/example; skipping.'), + contains( + 'No unit tests ran. Plugins are required to have unit tests.', + ), + contains('The following packages had errors:'), + contains( + 'plugin:\n' + ' No unit tests ran (use --exclude if this is intentional).', + ), + ]), + ); expect( - processRunner.recordedCalls, - orderedEquals([ - getTargetCheckCall(pluginExampleDirectory, 'macos'), - ])); + processRunner.recordedCalls, + orderedEquals([ + getTargetCheckCall(pluginExampleDirectory, 'macos'), + ]), + ); }); test('fails if unable to check for requested target', () async { final RepositoryPackage plugin1 = createFakePlugin( - 'plugin', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + 'plugin', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin1); processRunner.mockProcessesForExecutable['xcrun'] = [ - FakeProcessInfo( - MockProcess(exitCode: 1), ['xcodebuild', '-list']), + FakeProcessInfo(MockProcess(exitCode: 1), [ + 'xcodebuild', + '-list', + ]), ]; Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'native-test', - '--macos', - '--no-integration', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['native-test', '--macos', '--no-integration'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -1546,103 +1706,139 @@ public class FlutterActivityTest { ); expect( - processRunner.recordedCalls, - orderedEquals([ - getTargetCheckCall(pluginExampleDirectory, 'macos'), - ])); + processRunner.recordedCalls, + orderedEquals([ + getTargetCheckCall(pluginExampleDirectory, 'macos'), + ]), + ); }); test('Xcode warnings exceptions list', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline) - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); processRunner.mockProcessesForExecutable['xcrun'] = [ - FakeProcessInfo(MockProcess(stdout: jsonEncode(_kDeviceListMap)), - ['simctl', 'list']), - getMockXcodebuildListProcess( - ['RunnerTests', 'RunnerUITests']), + FakeProcessInfo( + MockProcess(stdout: jsonEncode(_kDeviceListMap)), + ['simctl', 'list'], + ), + getMockXcodebuildListProcess([ + 'RunnerTests', + 'RunnerUITests', + ]), ]; await runCapturingPrint(runner, [ 'native-test', '--ios', - '--xcode-warnings-exceptions=plugin' + '--xcode-warnings-exceptions=plugin', ]); expect( - processRunner.recordedCalls, - contains( - getRunTestCall(pluginExampleDirectory, 'ios', - destination: 'id=$_simulatorDeviceId', - treatWarningsAsErrors: false), - )); + processRunner.recordedCalls, + contains( + getRunTestCall( + pluginExampleDirectory, + 'ios', + destination: 'id=$_simulatorDeviceId', + treatWarningsAsErrors: false, + ), + ), + ); }); test('Xcode warnings exceptions file', () async { final File configFile = packagesDir.childFile('exceptions.yaml'); await configFile.writeAsString('- plugin'); - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline) - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); processRunner.mockProcessesForExecutable['xcrun'] = [ - FakeProcessInfo(MockProcess(stdout: jsonEncode(_kDeviceListMap)), - ['simctl', 'list']), - getMockXcodebuildListProcess( - ['RunnerTests', 'RunnerUITests']), + FakeProcessInfo( + MockProcess(stdout: jsonEncode(_kDeviceListMap)), + ['simctl', 'list'], + ), + getMockXcodebuildListProcess([ + 'RunnerTests', + 'RunnerUITests', + ]), ]; await runCapturingPrint(runner, [ 'native-test', '--ios', - '--xcode-warnings-exceptions=${configFile.path}' + '--xcode-warnings-exceptions=${configFile.path}', ]); expect( - processRunner.recordedCalls, - contains( - getRunTestCall(pluginExampleDirectory, 'ios', - destination: 'id=$_simulatorDeviceId', - treatWarningsAsErrors: false), - )); + processRunner.recordedCalls, + contains( + getRunTestCall( + pluginExampleDirectory, + 'ios', + destination: 'id=$_simulatorDeviceId', + treatWarningsAsErrors: false, + ), + ), + ); }); - test('treat warnings as errors if plugin not on exceptions list', - () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, + test( + 'treat warnings as errors if plugin not on exceptions list', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline) - }); + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); - final Directory pluginExampleDirectory = getExampleDir(plugin); + final Directory pluginExampleDirectory = getExampleDir(plugin); - processRunner.mockProcessesForExecutable['xcrun'] = [ - FakeProcessInfo(MockProcess(stdout: jsonEncode(_kDeviceListMap)), - ['simctl', 'list']), - getMockXcodebuildListProcess( - ['RunnerTests', 'RunnerUITests']), - ]; + processRunner.mockProcessesForExecutable['xcrun'] = [ + FakeProcessInfo( + MockProcess(stdout: jsonEncode(_kDeviceListMap)), + ['simctl', 'list'], + ), + getMockXcodebuildListProcess([ + 'RunnerTests', + 'RunnerUITests', + ]), + ]; - await runCapturingPrint(runner, [ - 'native-test', - '--ios', - '--xcode-warnings-exceptions=foo,bar' - ]); + await runCapturingPrint(runner, [ + 'native-test', + '--ios', + '--xcode-warnings-exceptions=foo,bar', + ]); - expect( + expect( processRunner.recordedCalls, contains( - getRunTestCall(pluginExampleDirectory, 'ios', - destination: 'id=$_simulatorDeviceId'), - )); - }); + getRunTestCall( + pluginExampleDirectory, + 'ios', + destination: 'id=$_simulatorDeviceId', + ), + ), + ); + }, + ); }); group('multiplatform', () { @@ -1662,18 +1858,29 @@ public class FlutterActivityTest { ); final Directory pluginExampleDirectory = getExampleDir(plugin); - final Directory androidFolder = - pluginExampleDirectory.childDirectory('android'); + final Directory androidFolder = pluginExampleDirectory.childDirectory( + 'android', + ); processRunner.mockProcessesForExecutable['xcrun'] = [ - getMockXcodebuildListProcess( - ['RunnerTests', 'RunnerUITests']), // iOS list - FakeProcessInfo(MockProcess(), - ['xcodebuild', 'clean', 'test']), // iOS run - getMockXcodebuildListProcess( - ['RunnerTests', 'RunnerUITests']), // macOS list - FakeProcessInfo(MockProcess(), - ['xcodebuild', 'clean', 'test']), // macOS run + getMockXcodebuildListProcess([ + 'RunnerTests', + 'RunnerUITests', + ]), // iOS list + FakeProcessInfo(MockProcess(), [ + 'xcodebuild', + 'clean', + 'test', + ]), // iOS run + getMockXcodebuildListProcess([ + 'RunnerTests', + 'RunnerUITests', + ]), // macOS list + FakeProcessInfo(MockProcess(), [ + 'xcodebuild', + 'clean', + 'test', + ]), // macOS run ]; final List output = await runCapturingPrint(runner, [ @@ -1686,46 +1893,57 @@ public class FlutterActivityTest { ]); expect( - output, - containsAll([ - contains('Running Android tests for plugin/example'), - contains('Successfully ran iOS xctest for plugin/example'), - contains('Successfully ran macOS xctest for plugin/example'), - ])); + output, + containsAll([ + contains('Running Android tests for plugin/example'), + contains('Successfully ran iOS xctest for plugin/example'), + contains('Successfully ran macOS xctest for plugin/example'), + ]), + ); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - androidFolder.childFile('gradlew').path, - const [ - 'app:testDebugUnitTest', - 'plugin:testDebugUnitTest', - ], - androidFolder.path), - getTargetCheckCall(pluginExampleDirectory, 'ios'), - getConfigOnlyDarwinBuildCall( - pluginExampleDirectory, FlutterPlatform.ios), - getRunTestCall(pluginExampleDirectory, 'ios', - destination: 'foo_destination'), - getTargetCheckCall(pluginExampleDirectory, 'macos'), - getConfigOnlyDarwinBuildCall( - pluginExampleDirectory, FlutterPlatform.macos), - getRunTestCall(pluginExampleDirectory, 'macos'), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(androidFolder.childFile('gradlew').path, const [ + 'app:testDebugUnitTest', + 'plugin:testDebugUnitTest', + ], androidFolder.path), + getTargetCheckCall(pluginExampleDirectory, 'ios'), + getConfigOnlyDarwinBuildCall( + pluginExampleDirectory, + FlutterPlatform.ios, + ), + getRunTestCall( + pluginExampleDirectory, + 'ios', + destination: 'foo_destination', + ), + getTargetCheckCall(pluginExampleDirectory, 'macos'), + getConfigOnlyDarwinBuildCall( + pluginExampleDirectory, + FlutterPlatform.macos, + ), + getRunTestCall(pluginExampleDirectory, 'macos'), + ]), + ); }); test('runs only macOS for a macOS plugin', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformMacOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); processRunner.mockProcessesForExecutable['xcrun'] = [ - getMockXcodebuildListProcess( - ['RunnerTests', 'RunnerUITests']), + getMockXcodebuildListProcess([ + 'RunnerTests', + 'RunnerUITests', + ]), ]; final List output = await runCapturingPrint(runner, [ @@ -1737,33 +1955,42 @@ public class FlutterActivityTest { ]); expect( - output, - containsAllInOrder([ - contains('No implementation for iOS.'), - contains('Successfully ran macOS xctest for plugin/example'), - ])); + output, + containsAllInOrder([ + contains('No implementation for iOS.'), + contains('Successfully ran macOS xctest for plugin/example'), + ]), + ); expect( - processRunner.recordedCalls, - orderedEquals([ - getTargetCheckCall(pluginExampleDirectory, 'macos'), - getConfigOnlyDarwinBuildCall( - pluginExampleDirectory, FlutterPlatform.macos), - getRunTestCall(pluginExampleDirectory, 'macos'), - ])); + processRunner.recordedCalls, + orderedEquals([ + getTargetCheckCall(pluginExampleDirectory, 'macos'), + getConfigOnlyDarwinBuildCall( + pluginExampleDirectory, + FlutterPlatform.macos, + ), + getRunTestCall(pluginExampleDirectory, 'macos'), + ]), + ); }); test('runs only iOS for a iOS plugin', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformIOS: const PlatformDetails(PlatformSupport.inline) - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformIOS: const PlatformDetails(PlatformSupport.inline), + }, + ); final Directory pluginExampleDirectory = getExampleDir(plugin); processRunner.mockProcessesForExecutable['xcrun'] = [ - getMockXcodebuildListProcess( - ['RunnerTests', 'RunnerUITests']), + getMockXcodebuildListProcess([ + 'RunnerTests', + 'RunnerUITests', + ]), ]; final List output = await runCapturingPrint(runner, [ @@ -1775,21 +2002,28 @@ public class FlutterActivityTest { ]); expect( - output, - containsAllInOrder([ - contains('No implementation for macOS.'), - contains('Successfully ran iOS xctest for plugin/example') - ])); + output, + containsAllInOrder([ + contains('No implementation for macOS.'), + contains('Successfully ran iOS xctest for plugin/example'), + ]), + ); expect( - processRunner.recordedCalls, - orderedEquals([ - getTargetCheckCall(pluginExampleDirectory, 'ios'), - getConfigOnlyDarwinBuildCall( - pluginExampleDirectory, FlutterPlatform.ios), - getRunTestCall(pluginExampleDirectory, 'ios', - destination: 'foo_destination'), - ])); + processRunner.recordedCalls, + orderedEquals([ + getTargetCheckCall(pluginExampleDirectory, 'ios'), + getConfigOnlyDarwinBuildCall( + pluginExampleDirectory, + FlutterPlatform.ios, + ), + getRunTestCall( + pluginExampleDirectory, + 'ios', + destination: 'foo_destination', + ), + ]), + ); }); test('skips when nothing is supported', () async { @@ -1806,13 +2040,14 @@ public class FlutterActivityTest { ]); expect( - output, - containsAllInOrder([ - contains('No implementation for Android.'), - contains('No implementation for iOS.'), - contains('No implementation for macOS.'), - contains('SKIPPING: Nothing to test for target platform(s).'), - ])); + output, + containsAllInOrder([ + contains('No implementation for Android.'), + contains('No implementation for iOS.'), + contains('No implementation for macOS.'), + contains('SKIPPING: Nothing to test for target platform(s).'), + ]), + ); expect(processRunner.recordedCalls, orderedEquals([])); }); @@ -1822,10 +2057,16 @@ public class FlutterActivityTest { 'plugin', packagesDir, platformSupport: { - platformMacOS: const PlatformDetails(PlatformSupport.inline, - hasDartCode: true, hasNativeCode: false), - platformWindows: const PlatformDetails(PlatformSupport.inline, - hasDartCode: true, hasNativeCode: false), + platformMacOS: const PlatformDetails( + PlatformSupport.inline, + hasDartCode: true, + hasNativeCode: false, + ), + platformWindows: const PlatformDetails( + PlatformSupport.inline, + hasDartCode: true, + hasNativeCode: false, + ), }, ); @@ -1838,12 +2079,13 @@ public class FlutterActivityTest { ]); expect( - output, - containsAllInOrder([ - contains('No native code for macOS.'), - contains('No native code for Windows.'), - contains('SKIPPING: Nothing to test for target platform(s).'), - ])); + output, + containsAllInOrder([ + contains('No native code for macOS.'), + contains('No native code for Windows.'), + contains('SKIPPING: Nothing to test for target platform(s).'), + ]), + ); expect(processRunner.recordedCalls, orderedEquals([])); }); @@ -1863,8 +2105,10 @@ public class FlutterActivityTest { ); processRunner.mockProcessesForExecutable['xcrun'] = [ - getMockXcodebuildListProcess( - ['RunnerTests', 'RunnerUITests']), + getMockXcodebuildListProcess([ + 'RunnerTests', + 'RunnerUITests', + ]), ]; // Simulate failing Android, but not iOS. @@ -1878,15 +2122,19 @@ public class FlutterActivityTest { [FakeProcessInfo(MockProcess(exitCode: 1))]; Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'native-test', - '--android', - '--ios', - '--ios-destination', - 'foo_destination', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + [ + 'native-test', + '--android', + '--ios', + '--ios-destination', + 'foo_destination', + ], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); @@ -1898,8 +2146,10 @@ public class FlutterActivityTest { contains('Running tests for iOS...'), contains('Successfully ran iOS xctest for plugin/example'), contains('The following packages had errors:'), - contains('plugin:\n' - ' Android') + contains( + 'plugin:\n' + ' Android', + ), ]), ); }); @@ -1929,19 +2179,23 @@ public class FlutterActivityTest { [FakeProcessInfo(MockProcess(exitCode: 1))]; // Simulate failing iOS. processRunner.mockProcessesForExecutable['xcrun'] = [ - FakeProcessInfo(MockProcess(exitCode: 1)) + FakeProcessInfo(MockProcess(exitCode: 1)), ]; Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'native-test', - '--android', - '--ios', - '--ios-destination', - 'foo_destination', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + [ + 'native-test', + '--android', + '--ios', + '--ios-destination', + 'foo_destination', + ], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); @@ -1951,9 +2205,11 @@ public class FlutterActivityTest { contains('Running tests for Android...'), contains('Running tests for iOS...'), contains('The following packages had errors:'), - contains('plugin:\n' - ' Android\n' - ' iOS') + contains( + 'plugin:\n' + ' Android\n' + ' iOS', + ), ]), ); }); @@ -1976,54 +2232,61 @@ public class FlutterActivityTest { // Returns the ProcessCall to expect for build the Windows unit tests for // the given plugin. ProcessCall getWindowsBuildCall(RepositoryPackage plugin, String? arch) { - Directory projectDir = getExampleDir(plugin) - .childDirectory('build') - .childDirectory('windows'); + Directory projectDir = getExampleDir( + plugin, + ).childDirectory('build').childDirectory('windows'); if (arch != null) { projectDir = projectDir.childDirectory(arch); } - return ProcessCall( - _fakeCmakeCommand, - [ - '--build', - projectDir.path, - '--target', - 'unit_tests', - '--config', - 'Debug' - ], - null); + return ProcessCall(_fakeCmakeCommand, [ + '--build', + projectDir.path, + '--target', + 'unit_tests', + '--config', + 'Debug', + ], null); } group('Windows x64', () { setUp(() { - final NativeTestCommand command = NativeTestCommand(packagesDir, - processRunner: processRunner, - platform: mockPlatform, - gitDir: gitDir, - abi: Abi.windowsX64); + final command = NativeTestCommand( + packagesDir, + processRunner: processRunner, + platform: mockPlatform, + gitDir: gitDir, + abi: Abi.windowsX64, + ); runner = CommandRunner( - 'native_test_command', 'Test for native_test_command'); + 'native_test_command', + 'Test for native_test_command', + ); runner.addCommand(command); }); test('runs unit tests', () async { - const String x64TestBinaryRelativePath = + const x64TestBinaryRelativePath = 'build/windows/x64/Debug/bar/plugin_test.exe'; - const String arm64TestBinaryRelativePath = + const arm64TestBinaryRelativePath = 'build/windows/arm64/Debug/bar/plugin_test.exe'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/$x64TestBinaryRelativePath', - 'example/$arm64TestBinaryRelativePath', - ], platformSupport: { - platformWindows: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'example/$x64TestBinaryRelativePath', + 'example/$arm64TestBinaryRelativePath', + ], + platformSupport: { + platformWindows: const PlatformDetails(PlatformSupport.inline), + }, + ); _createFakeCMakeCache(plugin, mockPlatform, _archDirX64); - final File testBinary = childFileWithSubcomponents(plugin.directory, - ['example', ...x64TestBinaryRelativePath.split('/')]); + final File testBinary = childFileWithSubcomponents( + plugin.directory, + ['example', ...x64TestBinaryRelativePath.split('/')], + ); final List output = await runCapturingPrint(runner, [ 'native-test', @@ -2040,26 +2303,31 @@ public class FlutterActivityTest { ); expect( - processRunner.recordedCalls, - orderedEquals([ - getWindowsBuildCall(plugin, _archDirX64), - ProcessCall(testBinary.path, const [], null), - ])); + processRunner.recordedCalls, + orderedEquals([ + getWindowsBuildCall(plugin, _archDirX64), + ProcessCall(testBinary.path, const [], null), + ]), + ); }); test('runs unit tests with legacy build output', () async { - const String testBinaryRelativePath = + const testBinaryRelativePath = 'build/windows/Debug/bar/plugin_test.exe'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/$testBinaryRelativePath' - ], platformSupport: { - platformWindows: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: ['example/$testBinaryRelativePath'], + platformSupport: { + platformWindows: const PlatformDetails(PlatformSupport.inline), + }, + ); _createFakeCMakeCache(plugin, mockPlatform, null); - final File testBinary = childFileWithSubcomponents(plugin.directory, - ['example', ...testBinaryRelativePath.split('/')]); + final File testBinary = childFileWithSubcomponents( + plugin.directory, + ['example', ...testBinaryRelativePath.split('/')], + ); final List output = await runCapturingPrint(runner, [ 'native-test', @@ -2076,30 +2344,36 @@ public class FlutterActivityTest { ); expect( - processRunner.recordedCalls, - orderedEquals([ - getWindowsBuildCall(plugin, null), - ProcessCall(testBinary.path, const [], null), - ])); + processRunner.recordedCalls, + orderedEquals([ + getWindowsBuildCall(plugin, null), + ProcessCall(testBinary.path, const [], null), + ]), + ); }); test('only runs debug unit tests', () async { - const String debugTestBinaryRelativePath = + const debugTestBinaryRelativePath = 'build/windows/x64/Debug/bar/plugin_test.exe'; - const String releaseTestBinaryRelativePath = + const releaseTestBinaryRelativePath = 'build/windows/x64/Release/bar/plugin_test.exe'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/$debugTestBinaryRelativePath', - 'example/$releaseTestBinaryRelativePath' - ], platformSupport: { - platformWindows: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'example/$debugTestBinaryRelativePath', + 'example/$releaseTestBinaryRelativePath', + ], + platformSupport: { + platformWindows: const PlatformDetails(PlatformSupport.inline), + }, + ); _createFakeCMakeCache(plugin, mockPlatform, _archDirX64); final File debugTestBinary = childFileWithSubcomponents( - plugin.directory, - ['example', ...debugTestBinaryRelativePath.split('/')]); + plugin.directory, + ['example', ...debugTestBinaryRelativePath.split('/')], + ); final List output = await runCapturingPrint(runner, [ 'native-test', @@ -2116,30 +2390,36 @@ public class FlutterActivityTest { ); expect( - processRunner.recordedCalls, - orderedEquals([ - getWindowsBuildCall(plugin, _archDirX64), - ProcessCall(debugTestBinary.path, const [], null), - ])); + processRunner.recordedCalls, + orderedEquals([ + getWindowsBuildCall(plugin, _archDirX64), + ProcessCall(debugTestBinary.path, const [], null), + ]), + ); }); test('only runs debug unit tests with legacy build output', () async { - const String debugTestBinaryRelativePath = + const debugTestBinaryRelativePath = 'build/windows/Debug/bar/plugin_test.exe'; - const String releaseTestBinaryRelativePath = + const releaseTestBinaryRelativePath = 'build/windows/Release/bar/plugin_test.exe'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/$debugTestBinaryRelativePath', - 'example/$releaseTestBinaryRelativePath' - ], platformSupport: { - platformWindows: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'example/$debugTestBinaryRelativePath', + 'example/$releaseTestBinaryRelativePath', + ], + platformSupport: { + platformWindows: const PlatformDetails(PlatformSupport.inline), + }, + ); _createFakeCMakeCache(plugin, mockPlatform, null); final File debugTestBinary = childFileWithSubcomponents( - plugin.directory, - ['example', ...debugTestBinaryRelativePath.split('/')]); + plugin.directory, + ['example', ...debugTestBinaryRelativePath.split('/')], + ); final List output = await runCapturingPrint(runner, [ 'native-test', @@ -2156,34 +2436,40 @@ public class FlutterActivityTest { ); expect( - processRunner.recordedCalls, - orderedEquals([ - getWindowsBuildCall(plugin, null), - ProcessCall(debugTestBinary.path, const [], null), - ])); + processRunner.recordedCalls, + orderedEquals([ + getWindowsBuildCall(plugin, null), + ProcessCall(debugTestBinary.path, const [], null), + ]), + ); }); test('fails if CMake has not been configured', () async { - createFakePlugin('plugin', packagesDir, - platformSupport: { - platformWindows: const PlatformDetails(PlatformSupport.inline), - }); + createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformWindows: const PlatformDetails(PlatformSupport.inline), + }, + ); Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'native-test', - '--windows', - '--no-integration', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['native-test', '--windows', '--no-integration'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ - contains('plugin:\n' - ' Examples must be built before testing.') + contains( + 'plugin:\n' + ' Examples must be built before testing.', + ), ]), ); @@ -2191,110 +2477,123 @@ public class FlutterActivityTest { }); test('fails if there are no unit tests', () async { - final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir, - platformSupport: { - platformWindows: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + platformSupport: { + platformWindows: const PlatformDetails(PlatformSupport.inline), + }, + ); _createFakeCMakeCache(plugin, mockPlatform, _archDirX64); Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'native-test', - '--windows', - '--no-integration', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['native-test', '--windows', '--no-integration'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, - containsAllInOrder([ - contains('No test binaries found.'), - ]), + containsAllInOrder([contains('No test binaries found.')]), ); expect( - processRunner.recordedCalls, - orderedEquals([ - getWindowsBuildCall(plugin, _archDirX64), - ])); + processRunner.recordedCalls, + orderedEquals([ + getWindowsBuildCall(plugin, _archDirX64), + ]), + ); }); test('fails if a unit test fails', () async { - const String testBinaryRelativePath = + const testBinaryRelativePath = 'build/windows/x64/Debug/bar/plugin_test.exe'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/$testBinaryRelativePath' - ], platformSupport: { - platformWindows: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: ['example/$testBinaryRelativePath'], + platformSupport: { + platformWindows: const PlatformDetails(PlatformSupport.inline), + }, + ); _createFakeCMakeCache(plugin, mockPlatform, _archDirX64); - final File testBinary = childFileWithSubcomponents(plugin.directory, - ['example', ...testBinaryRelativePath.split('/')]); + final File testBinary = childFileWithSubcomponents( + plugin.directory, + ['example', ...testBinaryRelativePath.split('/')], + ); processRunner.mockProcessesForExecutable[testBinary.path] = - [ - FakeProcessInfo(MockProcess(exitCode: 1)), - ]; + [FakeProcessInfo(MockProcess(exitCode: 1))]; Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'native-test', - '--windows', - '--no-integration', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['native-test', '--windows', '--no-integration'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, - containsAllInOrder([ - contains('Running plugin_test.exe...'), - ]), + containsAllInOrder([contains('Running plugin_test.exe...')]), ); expect( - processRunner.recordedCalls, - orderedEquals([ - getWindowsBuildCall(plugin, _archDirX64), - ProcessCall(testBinary.path, const [], null), - ])); + processRunner.recordedCalls, + orderedEquals([ + getWindowsBuildCall(plugin, _archDirX64), + ProcessCall(testBinary.path, const [], null), + ]), + ); }); }); group('Windows arm64', () { setUp(() { - final NativeTestCommand command = NativeTestCommand(packagesDir, - processRunner: processRunner, - platform: mockPlatform, - gitDir: gitDir, - abi: Abi.windowsArm64); + final command = NativeTestCommand( + packagesDir, + processRunner: processRunner, + platform: mockPlatform, + gitDir: gitDir, + abi: Abi.windowsArm64, + ); runner = CommandRunner( - 'native_test_command', 'Test for native_test_command'); + 'native_test_command', + 'Test for native_test_command', + ); runner.addCommand(command); }); test('runs unit tests', () async { - const String x64TestBinaryRelativePath = + const x64TestBinaryRelativePath = 'build/windows/x64/Debug/bar/plugin_test.exe'; - const String arm64TestBinaryRelativePath = + const arm64TestBinaryRelativePath = 'build/windows/arm64/Debug/bar/plugin_test.exe'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/$x64TestBinaryRelativePath', - 'example/$arm64TestBinaryRelativePath', - ], platformSupport: { - platformWindows: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'example/$x64TestBinaryRelativePath', + 'example/$arm64TestBinaryRelativePath', + ], + platformSupport: { + platformWindows: const PlatformDetails(PlatformSupport.inline), + }, + ); _createFakeCMakeCache(plugin, mockPlatform, _archDirArm64); - final File testBinary = childFileWithSubcomponents(plugin.directory, - ['example', ...arm64TestBinaryRelativePath.split('/')]); + final File testBinary = childFileWithSubcomponents( + plugin.directory, + ['example', ...arm64TestBinaryRelativePath.split('/')], + ); final List output = await runCapturingPrint(runner, [ 'native-test', @@ -2311,26 +2610,31 @@ public class FlutterActivityTest { ); expect( - processRunner.recordedCalls, - orderedEquals([ - getWindowsBuildCall(plugin, _archDirArm64), - ProcessCall(testBinary.path, const [], null), - ])); + processRunner.recordedCalls, + orderedEquals([ + getWindowsBuildCall(plugin, _archDirArm64), + ProcessCall(testBinary.path, const [], null), + ]), + ); }); test('falls back to x64 unit tests if arm64 is not built', () async { - const String x64TestBinaryRelativePath = + const x64TestBinaryRelativePath = 'build/windows/x64/Debug/bar/plugin_test.exe'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/$x64TestBinaryRelativePath', - ], platformSupport: { - platformWindows: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: ['example/$x64TestBinaryRelativePath'], + platformSupport: { + platformWindows: const PlatformDetails(PlatformSupport.inline), + }, + ); _createFakeCMakeCache(plugin, mockPlatform, _archDirX64); - final File testBinary = childFileWithSubcomponents(plugin.directory, - ['example', ...x64TestBinaryRelativePath.split('/')]); + final File testBinary = childFileWithSubcomponents( + plugin.directory, + ['example', ...x64TestBinaryRelativePath.split('/')], + ); final List output = await runCapturingPrint(runner, [ 'native-test', @@ -2347,30 +2651,36 @@ public class FlutterActivityTest { ); expect( - processRunner.recordedCalls, - orderedEquals([ - getWindowsBuildCall(plugin, _archDirX64), - ProcessCall(testBinary.path, const [], null), - ])); + processRunner.recordedCalls, + orderedEquals([ + getWindowsBuildCall(plugin, _archDirX64), + ProcessCall(testBinary.path, const [], null), + ]), + ); }); test('only runs debug unit tests', () async { - const String debugTestBinaryRelativePath = + const debugTestBinaryRelativePath = 'build/windows/arm64/Debug/bar/plugin_test.exe'; - const String releaseTestBinaryRelativePath = + const releaseTestBinaryRelativePath = 'build/windows/arm64/Release/bar/plugin_test.exe'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, extraFiles: [ - 'example/$debugTestBinaryRelativePath', - 'example/$releaseTestBinaryRelativePath' - ], platformSupport: { - platformWindows: const PlatformDetails(PlatformSupport.inline), - }); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + extraFiles: [ + 'example/$debugTestBinaryRelativePath', + 'example/$releaseTestBinaryRelativePath', + ], + platformSupport: { + platformWindows: const PlatformDetails(PlatformSupport.inline), + }, + ); _createFakeCMakeCache(plugin, mockPlatform, _archDirArm64); final File debugTestBinary = childFileWithSubcomponents( - plugin.directory, - ['example', ...debugTestBinaryRelativePath.split('/')]); + plugin.directory, + ['example', ...debugTestBinaryRelativePath.split('/')], + ); final List output = await runCapturingPrint(runner, [ 'native-test', @@ -2387,11 +2697,12 @@ public class FlutterActivityTest { ); expect( - processRunner.recordedCalls, - orderedEquals([ - getWindowsBuildCall(plugin, _archDirArm64), - ProcessCall(debugTestBinary.path, const [], null), - ])); + processRunner.recordedCalls, + orderedEquals([ + getWindowsBuildCall(plugin, _archDirArm64), + ProcessCall(debugTestBinary.path, const [], null), + ]), + ); }); }); }); diff --git a/script/tool/test/podspec_check_command_test.dart b/script/tool/test/podspec_check_command_test.dart index 0ff19b76aa83..dbd7fe9b276f 100644 --- a/script/tool/test/podspec_check_command_test.dart +++ b/script/tool/test/podspec_check_command_test.dart @@ -30,7 +30,7 @@ void _writeFakePodspec( final File file = plugin.directory .childDirectory(platform) .childFile('$pluginName.podspec'); - final String swiftWorkaround = includeSwiftWorkaround + final swiftWorkaround = includeSwiftWorkaround ? ''' s.${scopeSwiftWorkaround ? 'ios.' : ''}xcconfig = { 'LIBRARY_SEARCH_PATHS' => '\$(TOOLCHAIN_DIR)/usr/lib/swift/\$(PLATFORM_NAME)/ \$(SDKROOT)/usr/lib/swift', @@ -38,7 +38,7 @@ void _writeFakePodspec( } ''' : ''; - final String privacyManifest = includePrivacyManifest + final privacyManifest = includePrivacyManifest ? ''' s.resource_bundles = {'$pluginName' => ['Resources/PrivacyInfo.xcprivacy']} ''' @@ -85,41 +85,45 @@ void main() { final GitDir gitDir; (:packagesDir, :processRunner, gitProcessRunner: _, :gitDir) = configureBaseCommandMocks(platform: mockPlatform); - final PodspecCheckCommand command = PodspecCheckCommand( + final command = PodspecCheckCommand( packagesDir, processRunner: processRunner, platform: mockPlatform, gitDir: gitDir, ); - runner = - CommandRunner('podspec_test', 'Test for $PodspecCheckCommand'); + runner = CommandRunner( + 'podspec_test', + 'Test for $PodspecCheckCommand', + ); runner.addCommand(command); }); test('only runs on macOS', () async { - createFakePlugin('plugin1', packagesDir, - extraFiles: ['plugin1.podspec']); + createFakePlugin( + 'plugin1', + packagesDir, + extraFiles: ['plugin1.podspec'], + ); mockPlatform.isMacOS = false; Error? commandError; final List output = await runCapturingPrint( - runner, ['podspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['podspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); - expect( - processRunner.recordedCalls, - equals([]), - ); + expect(processRunner.recordedCalls, equals([])); expect( - output, - containsAllInOrder( - [contains('only supported on macOS')], - )); + output, + containsAllInOrder([contains('only supported on macOS')]), + ); }); test('runs pod lib lint on a podspec', () async { @@ -137,25 +141,23 @@ void main() { FakeProcessInfo(MockProcess()), ]; - final List output = - await runCapturingPrint(runner, ['podspec-check']); + final List output = await runCapturingPrint(runner, [ + 'podspec-check', + ]); expect( processRunner.recordedCalls, orderedEquals([ ProcessCall('which', const ['pod'], packagesDir.path), - ProcessCall( - 'pod', - [ - 'lib', - 'lint', - plugin - .platformDirectory(FlutterPlatform.ios) - .childFile('plugin1.podspec') - .path, - '--quick', - ], - packagesDir.path), + ProcessCall('pod', [ + 'lib', + 'lint', + plugin + .platformDirectory(FlutterPlatform.ios) + .childFile('plugin1.podspec') + .path, + '--quick', + ], packagesDir.path), ]), ); @@ -175,26 +177,24 @@ void main() { ); _writeFakePodspec(plugin, 'macos'); - final List output = - await runCapturingPrint(runner, ['podspec-check']); + final List output = await runCapturingPrint(runner, [ + 'podspec-check', + ]); expect(output, isNot(contains('FlutterMacOS.podspec'))); expect( processRunner.recordedCalls, orderedEquals([ ProcessCall('which', const ['pod'], packagesDir.path), - ProcessCall( - 'pod', - [ - 'lib', - 'lint', - plugin - .platformDirectory(FlutterPlatform.macos) - .childFile('plugin1.podspec') - .path, - '--quick', - ], - packagesDir.path), + ProcessCall('pod', [ + 'lib', + 'lint', + plugin + .platformDirectory(FlutterPlatform.macos) + .childFile('plugin1.podspec') + .path, + '--quick', + ], packagesDir.path), ]), ); }); @@ -210,19 +210,21 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['podspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['podspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder( - [ - contains('Unable to find "pod". Make sure it is in your path.'), - ], - )); + output, + containsAllInOrder([ + contains('Unable to find "pod". Make sure it is in your path.'), + ]), + ); }); test('fails if linting as a framework fails', () async { @@ -236,266 +238,300 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['podspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['podspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder( - [ - contains('The following packages had errors:'), - contains('plugin1:\n' - ' plugin1.podspec') - ], - )); - }); - - test('fails if an iOS Swift plugin is missing the search paths workaround', - () async { - final RepositoryPackage plugin = createFakePlugin( - 'plugin1', - packagesDir, - extraFiles: [ - 'ios/Classes/SomeSwift.swift', - 'ios/plugin1/Package.swift', - ], + output, + containsAllInOrder([ + contains('The following packages had errors:'), + contains( + 'plugin1:\n' + ' plugin1.podspec', + ), + ]), ); - _writeFakePodspec(plugin, 'ios'); - - Error? commandError; - final List output = await runCapturingPrint( - runner, ['podspec-check'], errorHandler: (Error e) { - commandError = e; - }); - - expect(commandError, isA()); + }); - expect( + test( + 'fails if an iOS Swift plugin is missing the search paths workaround', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin1', + packagesDir, + extraFiles: [ + 'ios/Classes/SomeSwift.swift', + 'ios/plugin1/Package.swift', + ], + ); + _writeFakePodspec(plugin, 'ios'); + + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['podspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); + + expect(commandError, isA()); + + expect( output, - containsAllInOrder( - [ - contains(r''' + containsAllInOrder([ + contains(r''' s.xcconfig = { 'LIBRARY_SEARCH_PATHS' => '$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)/ $(SDKROOT)/usr/lib/swift', 'LD_RUNPATH_SEARCH_PATHS' => '/usr/lib/swift', }'''), - contains('The following packages had errors:'), - contains('plugin1:\n' - ' plugin1.podspec') - ], - )); - }); + contains('The following packages had errors:'), + contains( + 'plugin1:\n' + ' plugin1.podspec', + ), + ]), + ); + }, + ); test( - 'fails if a shared-source Swift plugin is missing the search paths workaround', - () async { - final RepositoryPackage plugin = createFakePlugin('plugin1', packagesDir, - extraFiles: ['darwin/Classes/SomeSwift.swift']); - _writeFakePodspec(plugin, 'darwin'); - - Error? commandError; - final List output = await runCapturingPrint( - runner, ['podspec-check'], errorHandler: (Error e) { - commandError = e; - }); - - expect(commandError, isA()); - - expect( + 'fails if a shared-source Swift plugin is missing the search paths workaround', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin1', + packagesDir, + extraFiles: ['darwin/Classes/SomeSwift.swift'], + ); + _writeFakePodspec(plugin, 'darwin'); + + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['podspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); + + expect(commandError, isA()); + + expect( output, - containsAllInOrder( - [ - contains(r''' + containsAllInOrder([ + contains(r''' s.xcconfig = { 'LIBRARY_SEARCH_PATHS' => '$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)/ $(SDKROOT)/usr/lib/swift', 'LD_RUNPATH_SEARCH_PATHS' => '/usr/lib/swift', }'''), - contains('The following packages had errors:'), - contains('plugin1:\n' - ' plugin1.podspec') - ], - )); - }); + contains('The following packages had errors:'), + contains( + 'plugin1:\n' + ' plugin1.podspec', + ), + ]), + ); + }, + ); - test('does not require the search paths workaround for iOS Package.swift', - () async { - final RepositoryPackage plugin = createFakePlugin( - 'plugin1', - packagesDir, - extraFiles: ['ios/plugin1/Package.swift'], - ); - _writeFakePodspec(plugin, 'ios'); - - final List output = - await runCapturingPrint(runner, ['podspec-check']); - - expect( + test( + 'does not require the search paths workaround for iOS Package.swift', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin1', + packagesDir, + extraFiles: ['ios/plugin1/Package.swift'], + ); + _writeFakePodspec(plugin, 'ios'); + + final List output = await runCapturingPrint(runner, [ + 'podspec-check', + ]); + + expect( output, - containsAllInOrder( - [ - contains('Ran for 1 package(s)'), - ], - )); - }); + containsAllInOrder([contains('Ran for 1 package(s)')]), + ); + }, + ); - test('does not require the search paths workaround for Swift tests', - () async { - final RepositoryPackage plugin = createFakePlugin( - 'plugin1', - packagesDir, - extraFiles: [ - 'darwin/Tests/SharedTest.swift', - 'example/ios/RunnerTests/UnitTest.swift', - 'example/ios/RunnerUITests/UITest.swift', - ], - ); - _writeFakePodspec(plugin, 'ios'); - - final List output = - await runCapturingPrint(runner, ['podspec-check']); - - expect( + test( + 'does not require the search paths workaround for Swift tests', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin1', + packagesDir, + extraFiles: [ + 'darwin/Tests/SharedTest.swift', + 'example/ios/RunnerTests/UnitTest.swift', + 'example/ios/RunnerUITests/UITest.swift', + ], + ); + _writeFakePodspec(plugin, 'ios'); + + final List output = await runCapturingPrint(runner, [ + 'podspec-check', + ]); + + expect( output, - containsAllInOrder( - [ - contains('Ran for 1 package(s)'), - ], - )); - }); + containsAllInOrder([contains('Ran for 1 package(s)')]), + ); + }, + ); test( - 'does not require the search paths workaround for darwin Package.swift', - () async { - final RepositoryPackage plugin = createFakePlugin( - 'plugin1', - packagesDir, - extraFiles: ['darwin/plugin1/Package.swift'], - ); - _writeFakePodspec(plugin, 'darwin'); - - final List output = - await runCapturingPrint(runner, ['podspec-check']); - - expect( + 'does not require the search paths workaround for darwin Package.swift', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin1', + packagesDir, + extraFiles: ['darwin/plugin1/Package.swift'], + ); + _writeFakePodspec(plugin, 'darwin'); + + final List output = await runCapturingPrint(runner, [ + 'podspec-check', + ]); + + expect( output, - containsAllInOrder( - [ - contains('Ran for 1 package(s)'), - ], - )); - }); - - test('does not require the search paths workaround for macOS plugins', - () async { - final RepositoryPackage plugin = createFakePlugin('plugin1', packagesDir, - extraFiles: ['macos/Classes/SomeSwift.swift']); - _writeFakePodspec(plugin, 'macos'); - - final List output = - await runCapturingPrint(runner, ['podspec-check']); + containsAllInOrder([contains('Ran for 1 package(s)')]), + ); + }, + ); - expect( + test( + 'does not require the search paths workaround for macOS plugins', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin1', + packagesDir, + extraFiles: ['macos/Classes/SomeSwift.swift'], + ); + _writeFakePodspec(plugin, 'macos'); + + final List output = await runCapturingPrint(runner, [ + 'podspec-check', + ]); + + expect( output, - containsAllInOrder( - [ - contains('Ran for 1 package(s)'), - ], - )); - }); + containsAllInOrder([contains('Ran for 1 package(s)')]), + ); + }, + ); - test('does not require the search paths workaround for ObjC iOS plugins', - () async { - final RepositoryPackage plugin = createFakePlugin('plugin1', packagesDir, + test( + 'does not require the search paths workaround for ObjC iOS plugins', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin1', + packagesDir, extraFiles: [ 'ios/Classes/SomeObjC.h', - 'ios/Classes/SomeObjC.m' - ]); - _writeFakePodspec(plugin, 'ios'); + 'ios/Classes/SomeObjC.m', + ], + ); + _writeFakePodspec(plugin, 'ios'); - final List output = - await runCapturingPrint(runner, ['podspec-check']); + final List output = await runCapturingPrint(runner, [ + 'podspec-check', + ]); - expect( + expect( output, - containsAllInOrder( - [ - contains('Ran for 1 package(s)'), - ], - )); - }); + containsAllInOrder([contains('Ran for 1 package(s)')]), + ); + }, + ); test('passes if the search paths workaround is present', () async { - final RepositoryPackage plugin = createFakePlugin('plugin1', packagesDir, - extraFiles: ['ios/Classes/SomeSwift.swift']); + final RepositoryPackage plugin = createFakePlugin( + 'plugin1', + packagesDir, + extraFiles: ['ios/Classes/SomeSwift.swift'], + ); _writeFakePodspec(plugin, 'ios', includeSwiftWorkaround: true); - final List output = - await runCapturingPrint(runner, ['podspec-check']); + final List output = await runCapturingPrint(runner, [ + 'podspec-check', + ]); expect( - output, - containsAllInOrder( - [ - contains('Ran for 1 package(s)'), - ], - )); + output, + containsAllInOrder([contains('Ran for 1 package(s)')]), + ); }); - test('passes if the search paths workaround is present for iOS only', - () async { - final RepositoryPackage plugin = createFakePlugin('plugin1', packagesDir, - extraFiles: ['ios/Classes/SomeSwift.swift']); - _writeFakePodspec(plugin, 'ios', - includeSwiftWorkaround: true, scopeSwiftWorkaround: true); - - final List output = - await runCapturingPrint(runner, ['podspec-check']); - - expect( + test( + 'passes if the search paths workaround is present for iOS only', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin1', + packagesDir, + extraFiles: ['ios/Classes/SomeSwift.swift'], + ); + _writeFakePodspec( + plugin, + 'ios', + includeSwiftWorkaround: true, + scopeSwiftWorkaround: true, + ); + + final List output = await runCapturingPrint(runner, [ + 'podspec-check', + ]); + + expect( output, - containsAllInOrder( - [ - contains('Ran for 1 package(s)'), - ], - )); - }); + containsAllInOrder([contains('Ran for 1 package(s)')]), + ); + }, + ); - test('does not require the search paths workaround for Swift example code', - () async { - final RepositoryPackage plugin = - createFakePlugin('plugin1', packagesDir, extraFiles: [ - 'ios/Classes/SomeObjC.h', - 'ios/Classes/SomeObjC.m', - 'example/ios/Runner/AppDelegate.swift', - ]); - _writeFakePodspec(plugin, 'ios'); + test( + 'does not require the search paths workaround for Swift example code', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin1', + packagesDir, + extraFiles: [ + 'ios/Classes/SomeObjC.h', + 'ios/Classes/SomeObjC.m', + 'example/ios/Runner/AppDelegate.swift', + ], + ); + _writeFakePodspec(plugin, 'ios'); - final List output = - await runCapturingPrint(runner, ['podspec-check']); + final List output = await runCapturingPrint(runner, [ + 'podspec-check', + ]); - expect( + expect( output, - containsAllInOrder( - [ - contains('Ran for 1 package(s)'), - ], - )); - }); + containsAllInOrder([contains('Ran for 1 package(s)')]), + ); + }, + ); test('skips when there are no podspecs', () async { createFakePlugin('plugin1', packagesDir); - final List output = - await runCapturingPrint(runner, ['podspec-check']); + final List output = await runCapturingPrint(runner, [ + 'podspec-check', + ]); expect( - output, - containsAllInOrder( - [contains('SKIPPING: No podspecs.')], - )); + output, + containsAllInOrder([contains('SKIPPING: No podspecs.')]), + ); }); test('fails when an iOS plugin is missing a privacy manifest', () async { @@ -510,16 +546,20 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['podspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['podspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder( - [contains('No PrivacyInfo.xcprivacy file specified.')], - )); + output, + containsAllInOrder([ + contains('No PrivacyInfo.xcprivacy file specified.'), + ]), + ); }); test('passes when an iOS plugin has a privacy manifest', () async { @@ -532,14 +572,14 @@ void main() { ); _writeFakePodspec(plugin, 'ios', includePrivacyManifest: true); - final List output = - await runCapturingPrint(runner, ['podspec-check']); + final List output = await runCapturingPrint(runner, [ + 'podspec-check', + ]); expect( - output, - containsAllInOrder( - [contains('Ran for 1 package(s)')], - )); + output, + containsAllInOrder([contains('Ran for 1 package(s)')]), + ); }); test('fails when a macOS plugin is missing a privacy manifest', () async { @@ -554,16 +594,20 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['podspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['podspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder( - [contains('No PrivacyInfo.xcprivacy file specified.')], - )); + output, + containsAllInOrder([ + contains('No PrivacyInfo.xcprivacy file specified.'), + ]), + ); }); test('passes when a macOS plugin has a privacy manifest', () async { @@ -576,14 +620,14 @@ void main() { ); _writeFakePodspec(plugin, 'macos', includePrivacyManifest: true); - final List output = - await runCapturingPrint(runner, ['podspec-check']); + final List output = await runCapturingPrint(runner, [ + 'podspec-check', + ]); expect( - output, - containsAllInOrder( - [contains('Ran for 1 package(s)')], - )); + output, + containsAllInOrder([contains('Ran for 1 package(s)')]), + ); }); }); } diff --git a/script/tool/test/publish_check_command_test.dart b/script/tool/test/publish_check_command_test.dart index 97d6663bb32b..7b1b265e63a4 100644 --- a/script/tool/test/publish_check_command_test.dart +++ b/script/tool/test/publish_check_command_test.dart @@ -27,7 +27,7 @@ void main() { late CommandRunner runner; CommandRunner configureRunner({MockClient? httpClient}) { - final PublishCheckCommand publishCheckCommand = PublishCheckCommand( + final publishCheckCommand = PublishCheckCommand( packagesDir, processRunner: processRunner, platform: mockPlatform, @@ -66,17 +66,22 @@ void main() { await runCapturingPrint(runner, ['publish-check']); expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'flutter', - const ['pub', 'publish', '--', '--dry-run'], - plugin1.path), - ProcessCall( - 'flutter', - const ['pub', 'publish', '--', '--dry-run'], - plugin2.path), - ])); + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', const [ + 'pub', + 'publish', + '--', + '--dry-run', + ], plugin1.path), + ProcessCall('flutter', const [ + 'pub', + 'publish', + '--', + '--dry-run', + ], plugin2.path), + ]), + ); }); test('publish prepares dependencies of examples (when present)', () async { @@ -94,13 +99,13 @@ void main() { await runCapturingPrint(runner, ['publish-check']); // For plugin1, these are the expected pub get calls that will happen - final Iterable pubGetCalls = - plugin1.getExamples().map((RepositoryPackage example) { - return ProcessCall( - getFlutterCommand(mockPlatform), - const ['pub', 'get'], - example.path, - ); + final Iterable pubGetCalls = plugin1.getExamples().map(( + RepositoryPackage example, + ) { + return ProcessCall(getFlutterCommand(mockPlatform), const [ + 'pub', + 'get', + ], example.path); }); expect(pubGetCalls, hasLength(2)); @@ -109,15 +114,19 @@ void main() { orderedEquals([ // plugin1 has 2 examples, so there's some 'dart pub get' calls. ...pubGetCalls, - ProcessCall( - 'flutter', - const ['pub', 'publish', '--', '--dry-run'], - plugin1.path), + ProcessCall('flutter', const [ + 'pub', + 'publish', + '--', + '--dry-run', + ], plugin1.path), // plugin2 has no examples, so there's no extra 'dart pub get' calls. - ProcessCall( - 'flutter', - const ['pub', 'publish', '--', '--dry-run'], - plugin2.path), + ProcessCall('flutter', const [ + 'pub', + 'publish', + '--', + '--dry-run', + ], plugin2.path), ]), ); }); @@ -127,15 +136,20 @@ void main() { processRunner.mockProcessesForExecutable['flutter'] = [ FakeProcessInfo(MockProcess(), ['pub', 'get']), - FakeProcessInfo(MockProcess(exitCode: 1, stdout: 'Some error from pub'), - ['pub', 'publish']) + FakeProcessInfo( + MockProcess(exitCode: 1, stdout: 'Some error from pub'), + ['pub', 'publish'], + ), ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['publish-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['publish-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -153,86 +167,100 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['publish-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['publish-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, - containsAllInOrder([ - contains('No valid pubspec found.'), - ]), + containsAllInOrder([contains('No valid pubspec found.')]), ); }); test('fails if AUTHORS is missing', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); package.authorsFile.deleteSync(); Error? commandError; final List output = await runCapturingPrint( - runner, ['publish-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['publish-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - 'No AUTHORS file found. Packages must include an AUTHORS file.'), + 'No AUTHORS file found. Packages must include an AUTHORS file.', + ), ]), ); }); test('does not require AUTHORS for third-party', () async { final RepositoryPackage package = createFakePackage( - 'a_package', - packagesDir.parent - .childDirectory('third_party') - .childDirectory('packages')); + 'a_package', + packagesDir.parent + .childDirectory('third_party') + .childDirectory('packages'), + ); package.authorsFile.deleteSync(); - final List output = - await runCapturingPrint(runner, ['publish-check']); + final List output = await runCapturingPrint(runner, [ + 'publish-check', + ]); expect( output, - containsAllInOrder([ - contains('Running for a_package'), - ]), + containsAllInOrder([contains('Running for a_package')]), ); }); test('pass on prerelease if --allow-pre-release flag is on', () async { createFakePlugin('d', packagesDir); - final MockProcess process = MockProcess( - exitCode: 1, - stdout: 'Package has 1 warning.\n' - 'Packages with an SDK constraint on a pre-release of the Dart ' - 'SDK should themselves be published as a pre-release version.'); + final process = MockProcess( + exitCode: 1, + stdout: + 'Package has 1 warning.\n' + 'Packages with an SDK constraint on a pre-release of the Dart ' + 'SDK should themselves be published as a pre-release version.', + ); processRunner.mockProcessesForExecutable['flutter'] = [ FakeProcessInfo(MockProcess(), ['pub', 'get']), FakeProcessInfo(process, ['pub', 'publish']), ]; expect( - runCapturingPrint( - runner, ['publish-check', '--allow-pre-release']), - completes); + runCapturingPrint(runner, [ + 'publish-check', + '--allow-pre-release', + ]), + completes, + ); }); test('fail on prerelease if --allow-pre-release flag is off', () async { createFakePlugin('d', packagesDir); - final MockProcess process = MockProcess( - exitCode: 1, - stdout: 'Package has 1 warning.\n' - 'Packages with an SDK constraint on a pre-release of the Dart ' - 'SDK should themselves be published as a pre-release version.'); + final process = MockProcess( + exitCode: 1, + stdout: + 'Package has 1 warning.\n' + 'Packages with an SDK constraint on a pre-release of the Dart ' + 'SDK should themselves be published as a pre-release version.', + ); processRunner.mockProcessesForExecutable['flutter'] = [ FakeProcessInfo(MockProcess(), ['pub', 'get']), FakeProcessInfo(process, ['pub', 'publish']), @@ -240,16 +268,20 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['publish-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['publish-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - 'Packages with an SDK constraint on a pre-release of the Dart SDK'), + 'Packages with an SDK constraint on a pre-release of the Dart SDK', + ), contains('Unable to publish d'), ]), ); @@ -260,73 +292,91 @@ void main() { processRunner.mockProcessesForExecutable['flutter'] = [ FakeProcessInfo(MockProcess(), ['pub', 'get']), - FakeProcessInfo(MockProcess(stdout: 'Package has 0 warnings.'), - ['pub', 'publish']), + FakeProcessInfo( + MockProcess(stdout: 'Package has 0 warnings.'), + ['pub', 'publish'], + ), ]; - final List output = - await runCapturingPrint(runner, ['publish-check']); + final List output = await runCapturingPrint(runner, [ + 'publish-check', + ]); expect(output, isNot(contains(contains('ERROR:')))); }); test( - 'runs validation even for packages that are already published and reports failure', - () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '0.1.0'); - - final MockClient mockClient = MockClient((http.Request request) async { - if (request.url.pathSegments.last == 'a_package.json') { - return http.Response( + 'runs validation even for packages that are already published and reports failure', + () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '0.1.0', + ); + + final mockClient = MockClient((http.Request request) async { + if (request.url.pathSegments.last == 'a_package.json') { + return http.Response( json.encode({ 'name': 'a_package', - 'versions': [ - '0.0.1', - '0.1.0', - ], + 'versions': ['0.0.1', '0.1.0'], }), - 200); - } - return http.Response('', 500); - }); + 200, + ); + } + return http.Response('', 500); + }); - runner = configureRunner(httpClient: mockClient); + runner = configureRunner(httpClient: mockClient); - processRunner.mockProcessesForExecutable['flutter'] = [ - FakeProcessInfo(MockProcess(exitCode: 1, stdout: 'Some error from pub'), - ['pub', 'publish']) - ]; + processRunner.mockProcessesForExecutable['flutter'] = [ + FakeProcessInfo( + MockProcess(exitCode: 1, stdout: 'Some error from pub'), + ['pub', 'publish'], + ), + ]; - Error? commandError; - final List output = await runCapturingPrint( - runner, ['publish-check'], errorHandler: (Error e) { - commandError = e; - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['publish-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('Unable to publish a_package'), - ]), - ); - expect( + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains('Unable to publish a_package'), + ]), + ); + expect( processRunner.recordedCalls, contains( - ProcessCall( - 'flutter', - const ['pub', 'publish', '--', '--dry-run'], - package.path), - )); - }); + ProcessCall('flutter', const [ + 'pub', + 'publish', + '--', + '--dry-run', + ], package.path), + ), + ); + }, + ); test('skips packages that are marked as not for publishing', () async { - createFakePackage('a_package', packagesDir, - version: '0.1.0', publishTo: 'none'); + createFakePackage( + 'a_package', + packagesDir, + version: '0.1.0', + publishTo: 'none', + ); - final List output = - await runCapturingPrint(runner, ['publish-check']); + final List output = await runCapturingPrint(runner, [ + 'publish-check', + ]); expect( output, @@ -338,52 +388,62 @@ void main() { }); test( - 'runs validation even for packages that are already published and reports success', - () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '0.1.0'); - - final MockClient mockClient = MockClient((http.Request request) async { - if (request.url.pathSegments.last == 'a_package.json') { - return http.Response( + 'runs validation even for packages that are already published and reports success', + () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '0.1.0', + ); + + final mockClient = MockClient((http.Request request) async { + if (request.url.pathSegments.last == 'a_package.json') { + return http.Response( json.encode({ 'name': 'a_package', - 'versions': [ - '0.0.1', - '0.1.0', - ], + 'versions': ['0.0.1', '0.1.0'], }), - 200); - } - return http.Response('', 500); - }); + 200, + ); + } + return http.Response('', 500); + }); - runner = configureRunner(httpClient: mockClient); + runner = configureRunner(httpClient: mockClient); - final List output = - await runCapturingPrint(runner, ['publish-check']); + final List output = await runCapturingPrint(runner, [ + 'publish-check', + ]); - expect( - output, - containsAllInOrder([ - contains( - 'Package a_package version: 0.1.0 has already been published on pub.'), - ]), - ); - expect( + expect( + output, + containsAllInOrder([ + contains( + 'Package a_package version: 0.1.0 has already been published on pub.', + ), + ]), + ); + expect( processRunner.recordedCalls, contains( - ProcessCall( - 'flutter', - const ['pub', 'publish', '--', '--dry-run'], - package.path), - )); - }); + ProcessCall('flutter', const [ + 'pub', + 'publish', + '--', + '--dry-run', + ], package.path), + ), + ); + }, + ); group('pre-publish script', () { test('runs if present', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, examples: []); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + examples: [], + ); package.prePublishScript.createSync(recursive: true); final List output = await runCapturingPrint(runner, [ @@ -397,28 +457,26 @@ void main() { ]), ); expect( - processRunner.recordedCalls, - containsAllInOrder([ - ProcessCall( - 'dart', - const [ - 'pub', - 'get', - ], - package.directory.path), - ProcessCall( - 'dart', - const [ - 'run', - 'tool/pre_publish.dart', - ], - package.directory.path), - ])); + processRunner.recordedCalls, + containsAllInOrder([ + ProcessCall('dart', const [ + 'pub', + 'get', + ], package.directory.path), + ProcessCall('dart', const [ + 'run', + 'tool/pre_publish.dart', + ], package.directory.path), + ]), + ); }); test('runs before publish --dry-run', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, examples: []); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + examples: [], + ); package.prePublishScript.createSync(recursive: true); final List output = await runCapturingPrint(runner, [ @@ -432,111 +490,100 @@ void main() { ]), ); expect( - processRunner.recordedCalls, - containsAllInOrder([ - ProcessCall( - 'dart', - const [ - 'run', - 'tool/pre_publish.dart', - ], - package.directory.path), - ProcessCall( - 'flutter', - const [ - 'pub', - 'publish', - '--', - '--dry-run', - ], - package.directory.path), - ])); + processRunner.recordedCalls, + containsAllInOrder([ + ProcessCall('dart', const [ + 'run', + 'tool/pre_publish.dart', + ], package.directory.path), + ProcessCall('flutter', const [ + 'pub', + 'publish', + '--', + '--dry-run', + ], package.directory.path), + ]), + ); }); test('causes command failure if it fails', () async { final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - isFlutter: true, examples: []); + 'a_package', + packagesDir, + isFlutter: true, + examples: [], + ); package.prePublishScript.createSync(recursive: true); processRunner.mockProcessesForExecutable['dart'] = [ - FakeProcessInfo(MockProcess(exitCode: 1), - ['run']), // run tool/pre_publish.dart + FakeProcessInfo(MockProcess(exitCode: 1), [ + 'run', + ]), // run tool/pre_publish.dart ]; Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'publish-check', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['publish-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, - containsAllInOrder([ - contains('Pre-publish script failed.'), - ]), + containsAllInOrder([contains('Pre-publish script failed.')]), ); expect( - processRunner.recordedCalls, - containsAllInOrder([ - ProcessCall( - getFlutterCommand(mockPlatform), - const [ - 'pub', - 'get', - ], - package.directory.path), - ProcessCall( - 'dart', - const [ - 'run', - 'tool/pre_publish.dart', - ], - package.directory.path), - ])); + processRunner.recordedCalls, + containsAllInOrder([ + ProcessCall(getFlutterCommand(mockPlatform), const [ + 'pub', + 'get', + ], package.directory.path), + ProcessCall('dart', const [ + 'run', + 'tool/pre_publish.dart', + ], package.directory.path), + ]), + ); }); }); test( - '--machine: Log JSON with status:no-publish and correct human message, if there are no packages need to be published. ', - () async { - const Map httpResponseA = { - 'name': 'a', - 'versions': [ - '0.0.1', - '0.1.0', - ], - }; - - const Map httpResponseB = { - 'name': 'b', - 'versions': [ - '0.0.1', - '0.1.0', - '0.2.0', - ], - }; - - final MockClient mockClient = MockClient((http.Request request) async { - if (request.url.pathSegments.last == 'no_publish_a.json') { - return http.Response(json.encode(httpResponseA), 200); - } else if (request.url.pathSegments.last == 'no_publish_b.json') { - return http.Response(json.encode(httpResponseB), 200); - } - return http.Response('', 500); - }); + '--machine: Log JSON with status:no-publish and correct human message, if there are no packages need to be published. ', + () async { + const httpResponseA = { + 'name': 'a', + 'versions': ['0.0.1', '0.1.0'], + }; + + const httpResponseB = { + 'name': 'b', + 'versions': ['0.0.1', '0.1.0', '0.2.0'], + }; + + final mockClient = MockClient((http.Request request) async { + if (request.url.pathSegments.last == 'no_publish_a.json') { + return http.Response(json.encode(httpResponseA), 200); + } else if (request.url.pathSegments.last == 'no_publish_b.json') { + return http.Response(json.encode(httpResponseB), 200); + } + return http.Response('', 500); + }); - runner = configureRunner(httpClient: mockClient); + runner = configureRunner(httpClient: mockClient); - createFakePlugin('no_publish_a', packagesDir, version: '0.1.0'); - createFakePlugin('no_publish_b', packagesDir, version: '0.2.0'); + createFakePlugin('no_publish_a', packagesDir, version: '0.1.0'); + createFakePlugin('no_publish_b', packagesDir, version: '0.2.0'); - final List output = await runCapturingPrint( - runner, ['publish-check', '--machine']); + final List output = await runCapturingPrint(runner, [ + 'publish-check', + '--machine', + ]); - expect(output.first, r''' + expect(output.first, r''' { "status": "no-publish", "humanMessage": [ @@ -557,45 +604,42 @@ void main() { "No issues found!" ] }'''); - }); + }, + ); test( - '--machine: Log JSON with status:needs-publish and correct human message, if there is at least 1 plugin needs to be published.', - () async { - const Map httpResponseA = { - 'name': 'a', - 'versions': [ - '0.0.1', - '0.1.0', - ], - }; - - const Map httpResponseB = { - 'name': 'b', - 'versions': [ - '0.0.1', - '0.1.0', - ], - }; - - final MockClient mockClient = MockClient((http.Request request) async { - if (request.url.pathSegments.last == 'no_publish_a.json') { - return http.Response(json.encode(httpResponseA), 200); - } else if (request.url.pathSegments.last == 'no_publish_b.json') { - return http.Response(json.encode(httpResponseB), 200); - } - return http.Response('', 500); - }); + '--machine: Log JSON with status:needs-publish and correct human message, if there is at least 1 plugin needs to be published.', + () async { + const httpResponseA = { + 'name': 'a', + 'versions': ['0.0.1', '0.1.0'], + }; + + const httpResponseB = { + 'name': 'b', + 'versions': ['0.0.1', '0.1.0'], + }; + + final mockClient = MockClient((http.Request request) async { + if (request.url.pathSegments.last == 'no_publish_a.json') { + return http.Response(json.encode(httpResponseA), 200); + } else if (request.url.pathSegments.last == 'no_publish_b.json') { + return http.Response(json.encode(httpResponseB), 200); + } + return http.Response('', 500); + }); - runner = configureRunner(httpClient: mockClient); + runner = configureRunner(httpClient: mockClient); - createFakePlugin('no_publish_a', packagesDir, version: '0.1.0'); - createFakePlugin('no_publish_b', packagesDir, version: '0.2.0'); + createFakePlugin('no_publish_a', packagesDir, version: '0.1.0'); + createFakePlugin('no_publish_b', packagesDir, version: '0.2.0'); - final List output = await runCapturingPrint( - runner, ['publish-check', '--machine']); + final List output = await runCapturingPrint(runner, [ + 'publish-check', + '--machine', + ]); - expect(output.first, r''' + expect(output.first, r''' { "status": "needs-publish", "humanMessage": [ @@ -616,65 +660,72 @@ void main() { "No issues found!" ] }'''); - }); + }, + ); test( - '--machine: Log correct JSON, if there is at least 1 plugin contains error.', - () async { - const Map httpResponseA = { - 'name': 'a', - 'versions': [ - '0.0.1', - '0.1.0', - ], - }; - - const Map httpResponseB = { - 'name': 'b', - 'versions': [ - '0.0.1', - '0.1.0', - ], - }; - - final MockClient mockClient = MockClient((http.Request request) async { - print('url ${request.url}'); - print(request.url.pathSegments.last); - if (request.url.pathSegments.last == 'no_publish_a.json') { - return http.Response(json.encode(httpResponseA), 200); - } else if (request.url.pathSegments.last == 'no_publish_b.json') { - return http.Response(json.encode(httpResponseB), 200); - } - return http.Response('', 500); - }); + '--machine: Log correct JSON, if there is at least 1 plugin contains error.', + () async { + const httpResponseA = { + 'name': 'a', + 'versions': ['0.0.1', '0.1.0'], + }; + + const httpResponseB = { + 'name': 'b', + 'versions': ['0.0.1', '0.1.0'], + }; + + final mockClient = MockClient((http.Request request) async { + print('url ${request.url}'); + print(request.url.pathSegments.last); + if (request.url.pathSegments.last == 'no_publish_a.json') { + return http.Response(json.encode(httpResponseA), 200); + } else if (request.url.pathSegments.last == 'no_publish_b.json') { + return http.Response(json.encode(httpResponseB), 200); + } + return http.Response('', 500); + }); - runner = configureRunner(httpClient: mockClient); + runner = configureRunner(httpClient: mockClient); - final RepositoryPackage plugin = - createFakePlugin('no_publish_a', packagesDir, version: '0.1.0'); - createFakePlugin('no_publish_b', packagesDir, version: '0.2.0'); + final RepositoryPackage plugin = createFakePlugin( + 'no_publish_a', + packagesDir, + version: '0.1.0', + ); + createFakePlugin('no_publish_b', packagesDir, version: '0.2.0'); - await plugin.pubspecFile.writeAsString('bad-yaml'); + await plugin.pubspecFile.writeAsString('bad-yaml'); - bool hasError = false; - final List output = await runCapturingPrint( - runner, ['publish-check', '--machine'], + var hasError = false; + final List output = await runCapturingPrint( + runner, + ['publish-check', '--machine'], errorHandler: (Error error) { - expect(error, isA()); - hasError = true; - }); - expect(hasError, isTrue); + expect(error, isA()); + hasError = true; + }, + ); + expect(hasError, isTrue); - expect(output.first, contains(r''' + expect( + output.first, + contains( + r''' { "status": "error", "humanMessage": [ "\n============================================================\n|| Running for no_publish_a\n============================================================\n", - "Failed to parse `pubspec.yaml` at /packages/no_publish_a/pubspec.yaml: ParsedYamlException:''')); - // This is split into two checks since the details of the YamlException - // aren't controlled by this package, so asserting its exact format would - // make the test fragile to irrelevant changes in those details. - expect(output.first, contains(r''' + "Failed to parse `pubspec.yaml` at /packages/no_publish_a/pubspec.yaml: ParsedYamlException:''', + ), + ); + // This is split into two checks since the details of the YamlException + // aren't controlled by this package, so asserting its exact format would + // make the test fragile to irrelevant changes in those details. + expect( + output.first, + contains(r''' "No valid pubspec found.", "\n============================================================\n|| Running for no_publish_b\n============================================================\n", "url https://pub.dev/packages/no_publish_b.json", @@ -686,7 +737,9 @@ void main() { " no_publish_a", "See above for full details." ] -}''')); - }); +}'''), + ); + }, + ); }); } diff --git a/script/tool/test/publish_command_test.dart b/script/tool/test/publish_command_test.dart index 59fa146f38bb..f106f0349561 100644 --- a/script/tool/test/publish_command_test.dart +++ b/script/tool/test/publish_command_test.dart @@ -39,8 +39,12 @@ void main() { platform = MockPlatform(isLinux: true); processRunner = TestProcessRunner(); final GitDir gitDir; - (:packagesDir, processRunner: _, gitProcessRunner: _, :gitDir) = - configureBaseCommandMocks( + ( + :packagesDir, + processRunner: _, + gitProcessRunner: _, + :gitDir, + ) = configureBaseCommandMocks( platform: platform, customProcessRunner: processRunner, customGitProcessRunner: processRunner, @@ -48,9 +52,11 @@ void main() { platform.environment['HOME'] = '/home'; mockHttpResponses = >{}; - final MockClient mockClient = MockClient((http.Request request) async { - final String packageName = - request.url.pathSegments.last.replaceAll('.json', ''); + final mockClient = MockClient((http.Request request) async { + final String packageName = request.url.pathSegments.last.replaceAll( + '.json', + '', + ); final Map? response = mockHttpResponses[packageName]; if (response != null) { return http.Response(json.encode(response), 200); @@ -73,74 +79,85 @@ void main() { group('Initial validation', () { test('refuses to proceed with dirty files', () async { - final RepositoryPackage plugin = - createFakePlugin('foo', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'foo', + packagesDir, + examples: [], + ); - processRunner.mockProcessesForExecutable['git-status'] = - [ - FakeProcessInfo(MockProcess( - stdout: '?? ${plugin.directory.childFile('tmp').path}\n')) + processRunner + .mockProcessesForExecutable['git-status'] = [ + FakeProcessInfo( + MockProcess(stdout: '?? ${plugin.directory.childFile('tmp').path}\n'), + ), ]; Error? commandError; - final List output = - await runCapturingPrint(commandRunner, [ - 'publish', - '--packages=foo', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + commandRunner, + ['publish', '--packages=foo'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains("There are files in the package directory that haven't " - 'been saved in git. Refusing to publish these files:\n\n' - '?? /packages/foo/tmp\n\n' - 'If the directory should be clean, you can run `git clean -xdf && ' - 'git reset --hard HEAD` to wipe all local changes.'), - contains('foo:\n' - ' uncommitted changes'), - ])); + output, + containsAllInOrder([ + contains( + "There are files in the package directory that haven't " + 'been saved in git. Refusing to publish these files:\n\n' + '?? /packages/foo/tmp\n\n' + 'If the directory should be clean, you can run `git clean -xdf && ' + 'git reset --hard HEAD` to wipe all local changes.', + ), + contains( + 'foo:\n' + ' uncommitted changes', + ), + ]), + ); }); test("fails immediately if the remote doesn't exist", () async { createFakePlugin('foo', packagesDir, examples: []); processRunner.mockProcessesForExecutable['git-remote'] = - [ - FakeProcessInfo(MockProcess(exitCode: 1)), - ]; + [FakeProcessInfo(MockProcess(exitCode: 1))]; Error? commandError; final List output = await runCapturingPrint( - commandRunner, ['publish', '--packages=foo'], - errorHandler: (Error e) { - commandError = e; - }); + commandRunner, + ['publish', '--packages=foo'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains( - 'Unable to find URL for remote upstream; cannot push tags'), - ])); + output, + containsAllInOrder([ + contains('Unable to find URL for remote upstream; cannot push tags'), + ]), + ); }); }); group('pre-publish script', () { test('runs if present', () async { - final RepositoryPackage package = - createFakePackage('foo', packagesDir, examples: []); + final RepositoryPackage package = createFakePackage( + 'foo', + packagesDir, + examples: [], + ); package.prePublishScript.createSync(recursive: true); - final List output = - await runCapturingPrint(commandRunner, [ - 'publish', - '--packages=foo', - ]); + final List output = await runCapturingPrint( + commandRunner, + ['publish', '--packages=foo'], + ); expect( output, @@ -149,69 +166,62 @@ void main() { ]), ); expect( - processRunner.recordedCalls, - containsAllInOrder([ - ProcessCall( - 'dart', - const [ - 'pub', - 'get', - ], - package.directory.path), - ProcessCall( - 'dart', - const [ - 'run', - 'tool/pre_publish.dart', - ], - package.directory.path), - ])); + processRunner.recordedCalls, + containsAllInOrder([ + ProcessCall('dart', const [ + 'pub', + 'get', + ], package.directory.path), + ProcessCall('dart', const [ + 'run', + 'tool/pre_publish.dart', + ], package.directory.path), + ]), + ); }); test('causes command failure if it fails', () async { - final RepositoryPackage package = createFakePackage('foo', packagesDir, - isFlutter: true, examples: []); + final RepositoryPackage package = createFakePackage( + 'foo', + packagesDir, + isFlutter: true, + examples: [], + ); package.prePublishScript.createSync(recursive: true); processRunner.mockProcessesForExecutable['dart'] = [ - FakeProcessInfo(MockProcess(exitCode: 1), - ['run']), // run tool/pre_publish.dart + FakeProcessInfo(MockProcess(exitCode: 1), [ + 'run', + ]), // run tool/pre_publish.dart ]; Error? commandError; - final List output = - await runCapturingPrint(commandRunner, [ - 'publish', - '--packages=foo', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + commandRunner, + ['publish', '--packages=foo'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, - containsAllInOrder([ - contains('Pre-publish script failed.'), - ]), + containsAllInOrder([contains('Pre-publish script failed.')]), ); expect( - processRunner.recordedCalls, - containsAllInOrder([ - ProcessCall( - getFlutterCommand(platform), - const [ - 'pub', - 'get', - ], - package.directory.path), - ProcessCall( - 'dart', - const [ - 'run', - 'tool/pre_publish.dart', - ], - package.directory.path), - ])); + processRunner.recordedCalls, + containsAllInOrder([ + ProcessCall(getFlutterCommand(platform), const [ + 'pub', + 'get', + ], package.directory.path), + ProcessCall('dart', const [ + 'run', + 'tool/pre_publish.dart', + ], package.directory.path), + ]), + ); }); }); @@ -222,32 +232,41 @@ void main() { processRunner.mockProcessesForExecutable['flutter'] = [ FakeProcessInfo( - MockProcess( - stdout: 'Foo', - stderr: 'Bar', - stdoutEncoding: utf8, - stderrEncoding: utf8), - ['pub', 'publish']), // publish for plugin1 + MockProcess( + stdout: 'Foo', + stderr: 'Bar', + stdoutEncoding: utf8, + stderrEncoding: utf8, + ), + ['pub', 'publish'], + ), // publish for plugin1 FakeProcessInfo( - MockProcess( - stdout: 'Baz', stdoutEncoding: utf8, stderrEncoding: utf8), - ['pub', 'publish']), // publish for plugin2 + MockProcess( + stdout: 'Baz', + stdoutEncoding: utf8, + stderrEncoding: utf8, + ), + ['pub', 'publish'], + ), // publish for plugin2 ]; final List output = await runCapturingPrint( - commandRunner, ['publish', '--packages=plugin1,plugin2']); + commandRunner, + ['publish', '--packages=plugin1,plugin2'], + ); expect( - output, - containsAllInOrder([ - contains('Running `pub publish ` in /packages/plugin1...'), - contains('Foo'), - contains('Bar'), - contains('Package published!'), - contains('Running `pub publish ` in /packages/plugin2...'), - contains('Baz'), - contains('Package published!'), - ])); + output, + containsAllInOrder([ + contains('Running `pub publish ` in /packages/plugin1...'), + contains('Foo'), + contains('Bar'), + contains('Package published!'), + contains('Running `pub publish ` in /packages/plugin2...'), + contains('Baz'), + contains('Package published!'), + ]), + ); }); test('forwards input from the user to `pub publish`', () async { @@ -255,200 +274,233 @@ void main() { mockStdin.mockUserInputs.add(utf8.encode('user input')); - await runCapturingPrint( - commandRunner, ['publish', '--packages=foo']); - - expect(processRunner.mockPublishProcess.stdinMock.lines, - contains('user input')); - }); - - test('forwards --pub-publish-flags to pub publish', () async { - final RepositoryPackage plugin = - createFakePlugin('foo', packagesDir, examples: []); - await runCapturingPrint(commandRunner, [ 'publish', '--packages=foo', - '--pub-publish-flags', - '--dry-run,--server=bar' ]); expect( - processRunner.recordedCalls, - contains(ProcessCall( - 'flutter', - const ['pub', 'publish', '--dry-run', '--server=bar'], - plugin.path))); + processRunner.mockPublishProcess.stdinMock.lines, + contains('user input'), + ); }); - test( - '--skip-confirmation flag automatically adds --force to --pub-publish-flags', - () async { - createMockCredentialFile(); - final RepositoryPackage plugin = - createFakePlugin('foo', packagesDir, examples: []); + test('forwards --pub-publish-flags to pub publish', () async { + final RepositoryPackage plugin = createFakePlugin( + 'foo', + packagesDir, + examples: [], + ); await runCapturingPrint(commandRunner, [ 'publish', '--packages=foo', - '--skip-confirmation', '--pub-publish-flags', - '--server=bar' + '--dry-run,--server=bar', ]); expect( - processRunner.recordedCalls, - contains(ProcessCall( - 'flutter', - const ['pub', 'publish', '--server=bar', '--force'], - plugin.path))); + processRunner.recordedCalls, + contains( + ProcessCall('flutter', const [ + 'pub', + 'publish', + '--dry-run', + '--server=bar', + ], plugin.path), + ), + ); }); + test( + '--skip-confirmation flag automatically adds --force to --pub-publish-flags', + () async { + createMockCredentialFile(); + final RepositoryPackage plugin = createFakePlugin( + 'foo', + packagesDir, + examples: [], + ); + + await runCapturingPrint(commandRunner, [ + 'publish', + '--packages=foo', + '--skip-confirmation', + '--pub-publish-flags', + '--server=bar', + ]); + + expect( + processRunner.recordedCalls, + contains( + ProcessCall('flutter', const [ + 'pub', + 'publish', + '--server=bar', + '--force', + ], plugin.path), + ), + ); + }, + ); + test('--force is only added once, regardless of plugin count', () async { createMockCredentialFile(); - final RepositoryPackage plugin1 = - createFakePlugin('plugin_a', packagesDir, examples: []); - final RepositoryPackage plugin2 = - createFakePlugin('plugin_b', packagesDir, examples: []); + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin_a', + packagesDir, + examples: [], + ); + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin_b', + packagesDir, + examples: [], + ); await runCapturingPrint(commandRunner, [ 'publish', '--packages=plugin_a,plugin_b', '--skip-confirmation', '--pub-publish-flags', - '--server=bar' + '--server=bar', ]); expect( - processRunner.recordedCalls, - containsAllInOrder([ - ProcessCall( - 'flutter', - const ['pub', 'publish', '--server=bar', '--force'], - plugin1.path), - ProcessCall( - 'flutter', - const ['pub', 'publish', '--server=bar', '--force'], - plugin2.path), - ])); + processRunner.recordedCalls, + containsAllInOrder([ + ProcessCall('flutter', const [ + 'pub', + 'publish', + '--server=bar', + '--force', + ], plugin1.path), + ProcessCall('flutter', const [ + 'pub', + 'publish', + '--server=bar', + '--force', + ], plugin2.path), + ]), + ); }); - test('creates credential file from envirnoment variable if necessary', - () async { - createFakePlugin('foo', packagesDir, examples: []); - const String credentials = 'some credential'; - platform.environment['PUB_CREDENTIALS'] = credentials; - - await runCapturingPrint(commandRunner, [ - 'publish', - '--packages=foo', - '--skip-confirmation', - '--pub-publish-flags', - '--server=bar' - ]); - - final File credentialFile = - packagesDir.fileSystem.file(command.credentialsPath); - expect(credentialFile.existsSync(), true); - expect(credentialFile.readAsStringSync(), credentials); - }); + test( + 'creates credential file from envirnoment variable if necessary', + () async { + createFakePlugin('foo', packagesDir, examples: []); + const credentials = 'some credential'; + platform.environment['PUB_CREDENTIALS'] = credentials; + + await runCapturingPrint(commandRunner, [ + 'publish', + '--packages=foo', + '--skip-confirmation', + '--pub-publish-flags', + '--server=bar', + ]); + + final File credentialFile = packagesDir.fileSystem.file( + command.credentialsPath, + ); + expect(credentialFile.existsSync(), true); + expect(credentialFile.readAsStringSync(), credentials); + }, + ); test('throws if pub publish fails', () async { createFakePlugin('foo', packagesDir, examples: []); processRunner.mockProcessesForExecutable['flutter'] = [ - FakeProcessInfo(MockProcess(exitCode: 128), ['pub', 'publish']) + FakeProcessInfo(MockProcess(exitCode: 128), ['pub', 'publish']), ]; Error? commandError; - final List output = - await runCapturingPrint(commandRunner, [ - 'publish', - '--packages=foo', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + commandRunner, + ['publish', '--packages=foo'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Publishing foo failed.'), - ])); + output, + containsAllInOrder([contains('Publishing foo failed.')]), + ); }); test('publish, dry run', () async { - final RepositoryPackage plugin = - createFakePlugin('foo', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'foo', + packagesDir, + examples: [], + ); - final List output = - await runCapturingPrint(commandRunner, [ - 'publish', - '--packages=foo', - '--dry-run', - ]); + final List output = await runCapturingPrint( + commandRunner, + ['publish', '--packages=foo', '--dry-run'], + ); expect( - processRunner.recordedCalls - .map((ProcessCall call) => call.executable), - isNot(contains('git-push'))); + processRunner.recordedCalls.map((ProcessCall call) => call.executable), + isNot(contains('git-push')), + ); expect( - output, - containsAllInOrder([ - contains('=============== DRY RUN ==============='), - contains('Running for foo'), - contains('Running `pub publish ` in ${plugin.path}...'), - contains('Tagging release foo-v0.0.1...'), - contains('Pushing tag to upstream...'), - contains('Published foo successfully!'), - ])); + output, + containsAllInOrder([ + contains('=============== DRY RUN ==============='), + contains('Running for foo'), + contains('Running `pub publish ` in ${plugin.path}...'), + contains('Tagging release foo-v0.0.1...'), + contains('Pushing tag to upstream...'), + contains('Published foo successfully!'), + ]), + ); }); test('can publish non-flutter package', () async { - const String packageName = 'a_package'; + const packageName = 'a_package'; createFakePackage(packageName, packagesDir); - final List output = - await runCapturingPrint(commandRunner, [ - 'publish', - '--packages=$packageName', - ]); + final List output = await runCapturingPrint( + commandRunner, + ['publish', '--packages=$packageName'], + ); expect( output, - containsAllInOrder( - [ - contains('Running `pub publish ` in /packages/a_package...'), - contains('Package published!'), - ], - ), + containsAllInOrder([ + contains('Running `pub publish ` in /packages/a_package...'), + contains('Package published!'), + ]), ); }); test('skips publish with --tag-for-auto-publish', () async { - const String packageName = 'a_package'; + const packageName = 'a_package'; createFakePackage(packageName, packagesDir); - final List output = - await runCapturingPrint(commandRunner, [ - 'publish', - '--packages=$packageName', - '--tag-for-auto-publish', - ]); + final List output = await runCapturingPrint( + commandRunner, + [ + 'publish', + '--packages=$packageName', + '--tag-for-auto-publish', + ], + ); // There should be no variant of any command containing "publish". expect( - processRunner.recordedCalls - .map((ProcessCall call) => call.toString()), - isNot(contains(contains('publish')))); + processRunner.recordedCalls.map((ProcessCall call) => call.toString()), + isNot(contains(contains('publish'))), + ); // The output should indicate that it was tagged, not published. expect( output, - containsAllInOrder( - [ - contains('Tagged a_package successfully!'), - ], - ), + containsAllInOrder([ + contains('Tagged a_package successfully!'), + ]), ); }); }); @@ -461,8 +513,10 @@ void main() { '--packages=foo', ]); - expect(processRunner.recordedCalls, - contains(const ProcessCall('git-tag', ['foo-v0.0.1'], null))); + expect( + processRunner.recordedCalls, + contains(const ProcessCall('git-tag', ['foo-v0.0.1'], null)), + ); }); test('only if publishing succeeded', () async { @@ -473,24 +527,25 @@ void main() { ]; Error? commandError; - final List output = - await runCapturingPrint(commandRunner, [ - 'publish', - '--packages=foo', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + commandRunner, + ['publish', '--packages=foo'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Publishing foo failed.'), - ])); + output, + containsAllInOrder([contains('Publishing foo failed.')]), + ); expect( - processRunner.recordedCalls, - isNot(contains( - const ProcessCall('git-tag', ['foo-v0.0.1'], null)))); + processRunner.recordedCalls, + isNot( + contains(const ProcessCall('git-tag', ['foo-v0.0.1'], null)), + ), + ); }); test('when passed --tag-for-auto-publish', () async { @@ -501,8 +556,10 @@ void main() { '--tag-for-auto-publish', ]); - expect(processRunner.recordedCalls, - contains(const ProcessCall('git-tag', ['foo-v0.0.1'], null))); + expect( + processRunner.recordedCalls, + contains(const ProcessCall('git-tag', ['foo-v0.0.1'], null)), + ); }); }); @@ -512,46 +569,57 @@ void main() { mockStdin.readLineOutput = 'y'; - final List output = - await runCapturingPrint(commandRunner, [ - 'publish', - '--packages=foo', - ]); + final List output = await runCapturingPrint( + commandRunner, + ['publish', '--packages=foo'], + ); expect( - processRunner.recordedCalls, - contains(const ProcessCall( - 'git-push', ['upstream', 'foo-v0.0.1'], null))); + processRunner.recordedCalls, + contains( + const ProcessCall('git-push', [ + 'upstream', + 'foo-v0.0.1', + ], null), + ), + ); expect( - output, - containsAllInOrder([ - contains('Pushing tag to upstream...'), - contains('Published foo successfully!'), - ])); + output, + containsAllInOrder([ + contains('Pushing tag to upstream...'), + contains('Published foo successfully!'), + ]), + ); }); - test('does not ask for user input if the --skip-confirmation flag is on', - () async { - createMockCredentialFile(); - createFakePlugin('foo', packagesDir, examples: []); + test( + 'does not ask for user input if the --skip-confirmation flag is on', + () async { + createMockCredentialFile(); + createFakePlugin('foo', packagesDir, examples: []); - final List output = - await runCapturingPrint(commandRunner, [ - 'publish', - '--skip-confirmation', - '--packages=foo', - ]); + final List output = await runCapturingPrint( + commandRunner, + ['publish', '--skip-confirmation', '--packages=foo'], + ); - expect( + expect( processRunner.recordedCalls, - contains(const ProcessCall( - 'git-push', ['upstream', 'foo-v0.0.1'], null))); - expect( + contains( + const ProcessCall('git-push', [ + 'upstream', + 'foo-v0.0.1', + ], null), + ), + ); + expect( output, containsAllInOrder([ contains('Published foo successfully!'), - ])); - }); + ]), + ); + }, + ); test('when passed --tag-for-auto-publish', () async { createFakePlugin('foo', packagesDir, examples: []); @@ -563,33 +631,44 @@ void main() { ]); expect( - processRunner.recordedCalls, - contains(const ProcessCall( - 'git-push', ['upstream', 'foo-v0.0.1'], null))); + processRunner.recordedCalls, + contains( + const ProcessCall('git-push', [ + 'upstream', + 'foo-v0.0.1', + ], null), + ), + ); }); test('to upstream by default, dry run', () async { - final RepositoryPackage plugin = - createFakePlugin('foo', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'foo', + packagesDir, + examples: [], + ); mockStdin.readLineOutput = 'y'; final List output = await runCapturingPrint( - commandRunner, ['publish', '--packages=foo', '--dry-run']); + commandRunner, + ['publish', '--packages=foo', '--dry-run'], + ); expect( - processRunner.recordedCalls - .map((ProcessCall call) => call.executable), - isNot(contains('git-push'))); + processRunner.recordedCalls.map((ProcessCall call) => call.executable), + isNot(contains('git-push')), + ); expect( - output, - containsAllInOrder([ - contains('=============== DRY RUN ==============='), - contains('Running `pub publish ` in ${plugin.path}...'), - contains('Tagging release foo-v0.0.1...'), - contains('Pushing tag to upstream...'), - contains('Published foo successfully!'), - ])); + output, + containsAllInOrder([ + contains('=============== DRY RUN ==============='), + contains('Running `pub publish ` in ${plugin.path}...'), + contains('Tagging release foo-v0.0.1...'), + contains('Pushing tag to upstream...'), + contains('Published foo successfully!'), + ]), + ); }); test('to different remotes based on a flag', () async { @@ -597,23 +676,21 @@ void main() { mockStdin.readLineOutput = 'y'; - final List output = - await runCapturingPrint(commandRunner, [ - 'publish', - '--packages=foo', - '--remote', - 'origin', - ]); + final List output = await runCapturingPrint( + commandRunner, + ['publish', '--packages=foo', '--remote', 'origin'], + ); expect( - processRunner.recordedCalls, - contains(const ProcessCall( - 'git-push', ['origin', 'foo-v0.0.1'], null))); + processRunner.recordedCalls, + contains( + const ProcessCall('git-push', ['origin', 'foo-v0.0.1'], null), + ), + ); expect( - output, - containsAllInOrder([ - contains('Published foo successfully!'), - ])); + output, + containsAllInOrder([contains('Published foo successfully!')]), + ); }); }); @@ -623,31 +700,39 @@ void main() { processRunner.mockProcessesForExecutable['git-tag'] = [ FakeProcessInfo(MockProcess()), // Skip the initializeRun call. - FakeProcessInfo(MockProcess(stdout: 'foo-v0.0.1\n'), - ['--points-at', 'HEAD']) + FakeProcessInfo(MockProcess(stdout: 'foo-v0.0.1\n'), [ + '--points-at', + 'HEAD', + ]), ]; - await runCapturingPrint(commandRunner, - ['publish', '--packages=foo', '--already-tagged']); + await runCapturingPrint(commandRunner, [ + 'publish', + '--packages=foo', + '--already-tagged', + ]); }); test('fails if HEAD does not have the expected tag', () async { createFakePlugin('foo', packagesDir, examples: []); Error? commandError; - final List output = await runCapturingPrint(commandRunner, - ['publish', '--packages=foo', '--already-tagged'], - errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + commandRunner, + ['publish', '--packages=foo', '--already-tagged'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('The current checkout is not already tagged "foo-v0.0.1"'), - contains('missing tag'), - ])); + output, + containsAllInOrder([ + contains('The current checkout is not already tagged "foo-v0.0.1"'), + contains('missing tag'), + ]), + ); }); test('does not create or push tags', () async { @@ -655,21 +740,28 @@ void main() { processRunner.mockProcessesForExecutable['git-tag'] = [ FakeProcessInfo(MockProcess()), // Skip the initializeRun call. - FakeProcessInfo(MockProcess(stdout: 'foo-v0.0.1\n'), - ['--points-at', 'HEAD']) + FakeProcessInfo(MockProcess(stdout: 'foo-v0.0.1\n'), [ + '--points-at', + 'HEAD', + ]), ]; - await runCapturingPrint(commandRunner, - ['publish', '--packages=foo', '--already-tagged']); + await runCapturingPrint(commandRunner, [ + 'publish', + '--packages=foo', + '--already-tagged', + ]); expect( - processRunner.recordedCalls, - isNot(contains( - const ProcessCall('git-tag', ['foo-v0.0.1'], null)))); + processRunner.recordedCalls, + isNot( + contains(const ProcessCall('git-tag', ['foo-v0.0.1'], null)), + ), + ); expect( - processRunner.recordedCalls - .map((ProcessCall call) => call.executable), - isNot(contains('git-push'))); + processRunner.recordedCalls.map((ProcessCall call) => call.executable), + isNot(contains('git-push')), + ); }); }); @@ -686,100 +778,144 @@ void main() { }; // Non-federated - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); // federated final RepositoryPackage plugin2 = createFakePlugin( 'plugin2', packagesDir.childDirectory('plugin2'), ); processRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess( - stdout: '${plugin1.pubspecFile.path}\n' - '${plugin2.pubspecFile.path}\n')) + FakeProcessInfo( + MockProcess( + stdout: + '${plugin1.pubspecFile.path}\n' + '${plugin2.pubspecFile.path}\n', + ), + ), ]; mockStdin.readLineOutput = 'y'; - final List output = await runCapturingPrint(commandRunner, - ['publish', '--all-changed', '--base-sha=HEAD~']); + final List output = await runCapturingPrint( + commandRunner, + ['publish', '--all-changed', '--base-sha=HEAD~'], + ); expect( - output, - containsAllInOrder([ - contains( - 'Publishing all packages that have changed relative to "HEAD~"'), - contains('Running `pub publish ` in ${plugin1.path}...'), - contains('Running `pub publish ` in ${plugin2.path}...'), - contains('plugin1 - published'), - contains('plugin2/plugin2 - published'), - ])); + output, + containsAllInOrder([ + contains( + 'Publishing all packages that have changed relative to "HEAD~"', + ), + contains('Running `pub publish ` in ${plugin1.path}...'), + contains('Running `pub publish ` in ${plugin2.path}...'), + contains('plugin1 - published'), + contains('plugin2/plugin2 - published'), + ]), + ); expect( - processRunner.recordedCalls, - contains(const ProcessCall( - 'git-push', ['upstream', 'plugin1-v0.0.1'], null))); + processRunner.recordedCalls, + contains( + const ProcessCall('git-push', [ + 'upstream', + 'plugin1-v0.0.1', + ], null), + ), + ); expect( - processRunner.recordedCalls, - contains(const ProcessCall( - 'git-push', ['upstream', 'plugin2-v0.0.1'], null))); + processRunner.recordedCalls, + contains( + const ProcessCall('git-push', [ + 'upstream', + 'plugin2-v0.0.1', + ], null), + ), + ); }); - test('can release newly created plugins, while there are existing plugins', - () async { - mockHttpResponses['plugin0'] = { - 'name': 'plugin0', - 'versions': ['0.0.1'], - }; - - mockHttpResponses['plugin1'] = { - 'name': 'plugin1', - 'versions': [], - }; - - mockHttpResponses['plugin2'] = { - 'name': 'plugin2', - 'versions': [], - }; - - // The existing plugin. - createFakePlugin('plugin0', packagesDir); - // Non-federated - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); - // federated - final RepositoryPackage plugin2 = - createFakePlugin('plugin2', packagesDir.childDirectory('plugin2')); - - // Git results for plugin0 having been released already, and plugin1 and - // plugin2 being new. - processRunner.mockProcessesForExecutable['git-tag'] = [ - FakeProcessInfo(MockProcess(stdout: 'plugin0-v0.0.1\n')) - ]; - processRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess( - stdout: '${plugin1.pubspecFile.path}\n' - '${plugin2.pubspecFile.path}\n')) - ]; - - mockStdin.readLineOutput = 'y'; - - final List output = await runCapturingPrint(commandRunner, - ['publish', '--all-changed', '--base-sha=HEAD~']); + test( + 'can release newly created plugins, while there are existing plugins', + () async { + mockHttpResponses['plugin0'] = { + 'name': 'plugin0', + 'versions': ['0.0.1'], + }; + + mockHttpResponses['plugin1'] = { + 'name': 'plugin1', + 'versions': [], + }; + + mockHttpResponses['plugin2'] = { + 'name': 'plugin2', + 'versions': [], + }; + + // The existing plugin. + createFakePlugin('plugin0', packagesDir); + // Non-federated + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); + // federated + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir.childDirectory('plugin2'), + ); + + // Git results for plugin0 having been released already, and plugin1 and + // plugin2 being new. + processRunner.mockProcessesForExecutable['git-tag'] = [ + FakeProcessInfo(MockProcess(stdout: 'plugin0-v0.0.1\n')), + ]; + processRunner.mockProcessesForExecutable['git-diff'] = + [ + FakeProcessInfo( + MockProcess( + stdout: + '${plugin1.pubspecFile.path}\n' + '${plugin2.pubspecFile.path}\n', + ), + ), + ]; + + mockStdin.readLineOutput = 'y'; + + final List output = await runCapturingPrint( + commandRunner, + ['publish', '--all-changed', '--base-sha=HEAD~'], + ); - expect( + expect( output, containsAllInOrder([ 'Running `pub publish ` in ${plugin1.path}...\n', 'Running `pub publish ` in ${plugin2.path}...\n', - ])); - expect( + ]), + ); + expect( processRunner.recordedCalls, - contains(const ProcessCall( - 'git-push', ['upstream', 'plugin1-v0.0.1'], null))); - expect( + contains( + const ProcessCall('git-push', [ + 'upstream', + 'plugin1-v0.0.1', + ], null), + ), + ); + expect( processRunner.recordedCalls, - contains(const ProcessCall( - 'git-push', ['upstream', 'plugin2-v0.0.1'], null))); - }); + contains( + const ProcessCall('git-push', [ + 'upstream', + 'plugin2-v0.0.1', + ], null), + ), + ); + }, + ); test('can release newly created plugins, dry run', () async { mockHttpResponses['plugin1'] = { @@ -793,44 +929,50 @@ void main() { }; // Non-federated - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); // federated - final RepositoryPackage plugin2 = - createFakePlugin('plugin2', packagesDir.childDirectory('plugin2')); + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir.childDirectory('plugin2'), + ); processRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess( - stdout: '${plugin1.pubspecFile.path}\n' - '${plugin2.pubspecFile.path}\n')) + FakeProcessInfo( + MockProcess( + stdout: + '${plugin1.pubspecFile.path}\n' + '${plugin2.pubspecFile.path}\n', + ), + ), ]; mockStdin.readLineOutput = 'y'; final List output = await runCapturingPrint( - commandRunner, [ - 'publish', - '--all-changed', - '--base-sha=HEAD~', - '--dry-run' - ]); + commandRunner, + ['publish', '--all-changed', '--base-sha=HEAD~', '--dry-run'], + ); expect( - output, - containsAllInOrder([ - contains('=============== DRY RUN ==============='), - contains('Running `pub publish ` in ${plugin1.path}...'), - contains('Tagging release plugin1-v0.0.1...'), - contains('Pushing tag to upstream...'), - contains('Published plugin1 successfully!'), - contains('Running `pub publish ` in ${plugin2.path}...'), - contains('Tagging release plugin2-v0.0.1...'), - contains('Pushing tag to upstream...'), - contains('Published plugin2 successfully!'), - ])); + output, + containsAllInOrder([ + contains('=============== DRY RUN ==============='), + contains('Running `pub publish ` in ${plugin1.path}...'), + contains('Tagging release plugin1-v0.0.1...'), + contains('Pushing tag to upstream...'), + contains('Published plugin1 successfully!'), + contains('Running `pub publish ` in ${plugin2.path}...'), + contains('Tagging release plugin2-v0.0.1...'), + contains('Pushing tag to upstream...'), + contains('Published plugin2 successfully!'), + ]), + ); expect( - processRunner.recordedCalls - .map((ProcessCall call) => call.executable), - isNot(contains('git-push'))); + processRunner.recordedCalls.map((ProcessCall call) => call.executable), + isNot(contains('git-push')), + ); }); test('version change triggers releases.', () async { @@ -845,208 +987,301 @@ void main() { }; // Non-federated - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir, version: '0.0.2'); + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + version: '0.0.2', + ); // federated final RepositoryPackage plugin2 = createFakePlugin( - 'plugin2', packagesDir.childDirectory('plugin2'), - version: '0.0.2'); + 'plugin2', + packagesDir.childDirectory('plugin2'), + version: '0.0.2', + ); processRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess( - stdout: '${plugin1.pubspecFile.path}\n' - '${plugin2.pubspecFile.path}\n')) + FakeProcessInfo( + MockProcess( + stdout: + '${plugin1.pubspecFile.path}\n' + '${plugin2.pubspecFile.path}\n', + ), + ), ]; mockStdin.readLineOutput = 'y'; - final List output2 = await runCapturingPrint(commandRunner, - ['publish', '--all-changed', '--base-sha=HEAD~']); + final List output2 = await runCapturingPrint( + commandRunner, + ['publish', '--all-changed', '--base-sha=HEAD~'], + ); expect( - output2, - containsAllInOrder([ - contains('Running `pub publish ` in ${plugin1.path}...'), - contains('Published plugin1 successfully!'), - contains('Running `pub publish ` in ${plugin2.path}...'), - contains('Published plugin2 successfully!'), - ])); + output2, + containsAllInOrder([ + contains('Running `pub publish ` in ${plugin1.path}...'), + contains('Published plugin1 successfully!'), + contains('Running `pub publish ` in ${plugin2.path}...'), + contains('Published plugin2 successfully!'), + ]), + ); expect( - processRunner.recordedCalls, - contains(const ProcessCall( - 'git-push', ['upstream', 'plugin1-v0.0.2'], null))); + processRunner.recordedCalls, + contains( + const ProcessCall('git-push', [ + 'upstream', + 'plugin1-v0.0.2', + ], null), + ), + ); expect( - processRunner.recordedCalls, - contains(const ProcessCall( - 'git-push', ['upstream', 'plugin2-v0.0.2'], null))); + processRunner.recordedCalls, + contains( + const ProcessCall('git-push', [ + 'upstream', + 'plugin2-v0.0.2', + ], null), + ), + ); }); test( - 'delete package will not trigger publish but exit the command successfully!', - () async { - mockHttpResponses['plugin1'] = { - 'name': 'plugin1', - 'versions': ['0.0.1'], - }; - - mockHttpResponses['plugin2'] = { - 'name': 'plugin2', - 'versions': ['0.0.1'], - }; - - // Non-federated - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir, version: '0.0.2'); - // federated - final RepositoryPackage plugin2 = - createFakePlugin('plugin2', packagesDir.childDirectory('plugin2')); - plugin2.directory.deleteSync(recursive: true); - - processRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess( - stdout: '${plugin1.pubspecFile.path}\n' - '${plugin2.pubspecFile.path}\n')) - ]; - - mockStdin.readLineOutput = 'y'; - - final List output2 = await runCapturingPrint(commandRunner, - ['publish', '--all-changed', '--base-sha=HEAD~']); - expect( + 'delete package will not trigger publish but exit the command successfully!', + () async { + mockHttpResponses['plugin1'] = { + 'name': 'plugin1', + 'versions': ['0.0.1'], + }; + + mockHttpResponses['plugin2'] = { + 'name': 'plugin2', + 'versions': ['0.0.1'], + }; + + // Non-federated + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + version: '0.0.2', + ); + // federated + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir.childDirectory('plugin2'), + ); + plugin2.directory.deleteSync(recursive: true); + + processRunner.mockProcessesForExecutable['git-diff'] = + [ + FakeProcessInfo( + MockProcess( + stdout: + '${plugin1.pubspecFile.path}\n' + '${plugin2.pubspecFile.path}\n', + ), + ), + ]; + + mockStdin.readLineOutput = 'y'; + + final List output2 = await runCapturingPrint( + commandRunner, + ['publish', '--all-changed', '--base-sha=HEAD~'], + ); + expect( output2, containsAllInOrder([ contains('Running `pub publish ` in ${plugin1.path}...'), contains('Published plugin1 successfully!'), contains( - 'The pubspec file for plugin2/plugin2 does not exist, so no publishing will happen.\nSafe to ignore if the package is deleted in this commit.\n'), + 'The pubspec file for plugin2/plugin2 does not exist, so no publishing will happen.\nSafe to ignore if the package is deleted in this commit.\n', + ), contains('SKIPPING: package deleted'), contains('skipped (with warning)'), - ])); - expect( + ]), + ); + expect( processRunner.recordedCalls, - contains(const ProcessCall( - 'git-push', ['upstream', 'plugin1-v0.0.2'], null))); - }); - - test('Existing versions do not trigger release, also prints out message.', - () async { - mockHttpResponses['plugin1'] = { - 'name': 'plugin1', - 'versions': ['0.0.2'], - }; - - mockHttpResponses['plugin2'] = { - 'name': 'plugin2', - 'versions': ['0.0.2'], - }; - - // Non-federated - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir, version: '0.0.2'); - // federated - final RepositoryPackage plugin2 = createFakePlugin( - 'plugin2', packagesDir.childDirectory('plugin2'), - version: '0.0.2'); + contains( + const ProcessCall('git-push', [ + 'upstream', + 'plugin1-v0.0.2', + ], null), + ), + ); + }, + ); - processRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess( - stdout: '${plugin1.pubspecFile.path}\n' - '${plugin2.pubspecFile.path}\n')) - ]; - processRunner.mockProcessesForExecutable['git-tag'] = [ - FakeProcessInfo(MockProcess( - stdout: 'plugin1-v0.0.2\n' - 'plugin2-v0.0.2\n')) - ]; + test( + 'Existing versions do not trigger release, also prints out message.', + () async { + mockHttpResponses['plugin1'] = { + 'name': 'plugin1', + 'versions': ['0.0.2'], + }; + + mockHttpResponses['plugin2'] = { + 'name': 'plugin2', + 'versions': ['0.0.2'], + }; + + // Non-federated + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + version: '0.0.2', + ); + // federated + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir.childDirectory('plugin2'), + version: '0.0.2', + ); + + processRunner.mockProcessesForExecutable['git-diff'] = + [ + FakeProcessInfo( + MockProcess( + stdout: + '${plugin1.pubspecFile.path}\n' + '${plugin2.pubspecFile.path}\n', + ), + ), + ]; + processRunner.mockProcessesForExecutable['git-tag'] = [ + FakeProcessInfo( + MockProcess( + stdout: + 'plugin1-v0.0.2\n' + 'plugin2-v0.0.2\n', + ), + ), + ]; - final List output = await runCapturingPrint(commandRunner, - ['publish', '--all-changed', '--base-sha=HEAD~']); + final List output = await runCapturingPrint( + commandRunner, + ['publish', '--all-changed', '--base-sha=HEAD~'], + ); - expect( + expect( output, containsAllInOrder([ contains('plugin1 0.0.2 has already been published'), contains('SKIPPING: already published'), contains('plugin2 0.0.2 has already been published'), contains('SKIPPING: already published'), - ])); + ]), + ); - expect( - processRunner.recordedCalls - .map((ProcessCall call) => call.executable), - isNot(contains('git-push'))); - }); + expect( + processRunner.recordedCalls.map( + (ProcessCall call) => call.executable, + ), + isNot(contains('git-push')), + ); + }, + ); test( - 'Existing versions do not trigger release, but fail if the tags do not exist.', - () async { - mockHttpResponses['plugin1'] = { - 'name': 'plugin1', - 'versions': ['0.0.2'], - }; - - mockHttpResponses['plugin2'] = { - 'name': 'plugin2', - 'versions': ['0.0.2'], - }; - - // Non-federated - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir, version: '0.0.2'); - // federated - final RepositoryPackage plugin2 = createFakePlugin( - 'plugin2', packagesDir.childDirectory('plugin2'), - version: '0.0.2'); - - processRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess( - stdout: '${plugin1.pubspecFile.path}\n' - '${plugin2.pubspecFile.path}\n')) - ]; - - Error? commandError; - final List output = await runCapturingPrint(commandRunner, + 'Existing versions do not trigger release, but fail if the tags do not exist.', + () async { + mockHttpResponses['plugin1'] = { + 'name': 'plugin1', + 'versions': ['0.0.2'], + }; + + mockHttpResponses['plugin2'] = { + 'name': 'plugin2', + 'versions': ['0.0.2'], + }; + + // Non-federated + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + version: '0.0.2', + ); + // federated + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir.childDirectory('plugin2'), + version: '0.0.2', + ); + + processRunner.mockProcessesForExecutable['git-diff'] = + [ + FakeProcessInfo( + MockProcess( + stdout: + '${plugin1.pubspecFile.path}\n' + '${plugin2.pubspecFile.path}\n', + ), + ), + ]; + + Error? commandError; + final List output = await runCapturingPrint( + commandRunner, ['publish', '--all-changed', '--base-sha=HEAD~'], errorHandler: (Error e) { - commandError = e; - }); + commandError = e; + }, + ); - expect(commandError, isA()); - expect( + expect(commandError, isA()); + expect( output, containsAllInOrder([ - contains('plugin1 0.0.2 has already been published, ' - 'however the git release tag (plugin1-v0.0.2) was not found.'), - contains('plugin2 0.0.2 has already been published, ' - 'however the git release tag (plugin2-v0.0.2) was not found.'), - ])); - expect( - processRunner.recordedCalls - .map((ProcessCall call) => call.executable), - isNot(contains('git-push'))); - }); + contains( + 'plugin1 0.0.2 has already been published, ' + 'however the git release tag (plugin1-v0.0.2) was not found.', + ), + contains( + 'plugin2 0.0.2 has already been published, ' + 'however the git release tag (plugin2-v0.0.2) was not found.', + ), + ]), + ); + expect( + processRunner.recordedCalls.map( + (ProcessCall call) => call.executable, + ), + isNot(contains('git-push')), + ); + }, + ); test('No version change does not release any plugins', () async { // Non-federated - final RepositoryPackage plugin1 = - createFakePlugin('plugin1', packagesDir); + final RepositoryPackage plugin1 = createFakePlugin( + 'plugin1', + packagesDir, + ); // federated - final RepositoryPackage plugin2 = - createFakePlugin('plugin2', packagesDir.childDirectory('plugin2')); + final RepositoryPackage plugin2 = createFakePlugin( + 'plugin2', + packagesDir.childDirectory('plugin2'), + ); processRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess( - stdout: '${plugin1.libDirectory.childFile('plugin1.dart').path}\n' - '${plugin2.libDirectory.childFile('plugin2.dart').path}\n')) + FakeProcessInfo( + MockProcess( + stdout: + '${plugin1.libDirectory.childFile('plugin1.dart').path}\n' + '${plugin2.libDirectory.childFile('plugin2.dart').path}\n', + ), + ), ]; - final List output = await runCapturingPrint(commandRunner, - ['publish', '--all-changed', '--base-sha=HEAD~']); + final List output = await runCapturingPrint( + commandRunner, + ['publish', '--all-changed', '--base-sha=HEAD~'], + ); expect(output, containsAllInOrder(['Ran for 0 package(s)'])); expect( - processRunner.recordedCalls - .map((ProcessCall call) => call.executable), - isNot(contains('git-push'))); + processRunner.recordedCalls.map((ProcessCall call) => call.executable), + isNot(contains('git-push')), + ); }); test('Do not release flutter_plugin_tools', () async { @@ -1055,31 +1290,39 @@ void main() { 'versions': [], }; - final RepositoryPackage flutterPluginTools = - createFakePlugin('flutter_plugin_tools', packagesDir); + final RepositoryPackage flutterPluginTools = createFakePlugin( + 'flutter_plugin_tools', + packagesDir, + ); processRunner.mockProcessesForExecutable['git-diff'] = [ FakeProcessInfo( - MockProcess(stdout: flutterPluginTools.pubspecFile.path)) + MockProcess(stdout: flutterPluginTools.pubspecFile.path), + ), ]; - final List output = await runCapturingPrint(commandRunner, - ['publish', '--all-changed', '--base-sha=HEAD~']); + final List output = await runCapturingPrint( + commandRunner, + ['publish', '--all-changed', '--base-sha=HEAD~'], + ); expect( - output, - containsAllInOrder([ - contains( - 'SKIPPING: publishing flutter_plugin_tools via the tool is not supported') - ])); - expect( - output.contains( - 'Running `pub publish ` in ${flutterPluginTools.path}...', + output, + containsAllInOrder([ + contains( + 'SKIPPING: publishing flutter_plugin_tools via the tool is not supported', ), - isFalse); + ]), + ); + expect( + output.contains( + 'Running `pub publish ` in ${flutterPluginTools.path}...', + ), + isFalse, + ); expect( - processRunner.recordedCalls - .map((ProcessCall call) => call.executable), - isNot(contains('git-push'))); + processRunner.recordedCalls.map((ProcessCall call) => call.executable), + isNot(contains('git-push')), + ); }); }); @@ -1090,7 +1333,9 @@ void main() { command = PublishCommand(packagesDir, platform: platform); expect( - command.credentialsPath, '/xdghome/config/dart/pub-credentials.json'); + command.credentialsPath, + '/xdghome/config/dart/pub-credentials.json', + ); }); test('Linux without XDG', () async { @@ -1099,7 +1344,9 @@ void main() { command = PublishCommand(packagesDir, platform: platform); expect( - command.credentialsPath, '/home/.config/dart/pub-credentials.json'); + command.credentialsPath, + '/home/.config/dart/pub-credentials.json', + ); }); test('macOS', () async { @@ -1107,8 +1354,10 @@ void main() { platform.environment['HOME'] = '/Users/someuser'; command = PublishCommand(packagesDir, platform: platform); - expect(command.credentialsPath, - '/Users/someuser/Library/Application Support/dart/pub-credentials.json'); + expect( + command.credentialsPath, + '/Users/someuser/Library/Application Support/dart/pub-credentials.json', + ); }); test('Windows', () async { @@ -1116,8 +1365,10 @@ void main() { platform.environment['APPDATA'] = r'C:\Users\SomeUser\AppData'; command = PublishCommand(packagesDir, platform: platform); - expect(command.credentialsPath, - r'C:\Users\SomeUser\AppData\dart\pub-credentials.json'); + expect( + command.credentialsPath, + r'C:\Users\SomeUser\AppData\dart\pub-credentials.json', + ); }); }); } @@ -1129,10 +1380,16 @@ class TestProcessRunner extends RecordingProcessRunner { late MockProcess mockPublishProcess; @override - Future start(String executable, List args, - {Directory? workingDirectory}) async { - final io.Process process = - await super.start(executable, args, workingDirectory: workingDirectory); + Future start( + String executable, + List args, { + Directory? workingDirectory, + }) async { + final io.Process process = await super.start( + executable, + args, + workingDirectory: workingDirectory, + ); if (executable == 'flutter' && args.isNotEmpty && args[0] == 'pub' && @@ -1155,17 +1412,25 @@ class MockStdin extends Mock implements io.Stdin { } @override - StreamSubscription> listen(void Function(List event)? onData, - {Function? onError, void Function()? onDone, bool? cancelOnError}) { - return _controller.stream.listen(onData, - onError: onError, onDone: onDone, cancelOnError: cancelOnError); + StreamSubscription> listen( + void Function(List event)? onData, { + Function? onError, + void Function()? onDone, + bool? cancelOnError, + }) { + return _controller.stream.listen( + onData, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); } @override - String? readLineSync( - {Encoding encoding = io.systemEncoding, - bool retainNewlines = false}) => - readLineOutput; + String? readLineSync({ + Encoding encoding = io.systemEncoding, + bool retainNewlines = false, + }) => readLineOutput; void _addUserInputsToSteam(List input) => _controller.add(input); } diff --git a/script/tool/test/pubspec_check_command_test.dart b/script/tool/test/pubspec_check_command_test.dart index 12e8c2b89d60..4a84727b9132 100644 --- a/script/tool/test/pubspec_check_command_test.dart +++ b/script/tool/test/pubspec_check_command_test.dart @@ -33,18 +33,19 @@ String _headerSection( String? description, }) { final String repositoryPath = repositoryPackagesDirRelativePath ?? name; - final List repoLinkPathComponents = [ + final repoLinkPathComponents = [ repository, 'tree', repositoryBranch, 'packages', repositoryPath, ]; - final String repoLink = - 'https://github.com/${repoLinkPathComponents.join('/')}'; - final String issueTrackerLink = 'https://github.com/flutter/flutter/issues?' + final repoLink = 'https://github.com/${repoLinkPathComponents.join('/')}'; + final issueTrackerLink = + 'https://github.com/flutter/flutter/issues?' 'q=is%3Aissue+is%3Aopen+label%3A%22p%3A+$name%22'; - description ??= 'A test package for validating that the pubspec.yaml ' + description ??= + 'A test package for validating that the pubspec.yaml ' 'follows repo best practices.'; return ''' name: $name @@ -75,7 +76,8 @@ String _flutterSection({ Map> pluginPlatformDetails = const >{}, }) { - String pluginEntry = ''' + var pluginEntry = + ''' plugin: ${implementedPackage == null ? '' : ' implements: $implementedPackage'} platforms: @@ -83,11 +85,13 @@ ${implementedPackage == null ? '' : ' implements: $implementedPackage'} for (final MapEntry> platform in pluginPlatformDetails.entries) { - pluginEntry += ''' + pluginEntry += + ''' ${platform.key}: '''; for (final MapEntry detail in platform.value.entries) { - pluginEntry += ''' + pluginEntry += + ''' ${detail.key}: ${detail.value} '''; } @@ -99,8 +103,9 @@ ${isPlugin ? pluginEntry : ''} '''; } -String _dependenciesSection( - [List extraDependencies = const []]) { +String _dependenciesSection([ + List extraDependencies = const [], +]) { return ''' dependencies: flutter: @@ -109,8 +114,9 @@ ${extraDependencies.map((String dep) => ' $dep').join('\n')} '''; } -String _devDependenciesSection( - [List extraDependencies = const []]) { +String _devDependenciesSection([ + List extraDependencies = const [], +]) { return ''' dev_dependencies: flutter_test: @@ -145,7 +151,7 @@ void main() { final GitDir gitDir; (:packagesDir, :processRunner, gitProcessRunner: _, :gitDir) = configureBaseCommandMocks(platform: mockPlatform); - final PubspecCheckCommand command = PubspecCheckCommand( + final command = PubspecCheckCommand( packagesDir, processRunner: processRunner, platform: mockPlatform, @@ -153,7 +159,9 @@ void main() { ); runner = CommandRunner( - 'pubspec_check_command', 'Test for pubspec_check_command'); + 'pubspec_check_command', + 'Test for pubspec_check_command', + ); runner.addCommand(command); }); @@ -171,12 +179,7 @@ ${_falseSecretsSection()} '''); plugin.getExamples().first.pubspecFile.writeAsStringSync(''' -${_headerSection( - 'plugin_example', - publishable: false, - includeRepository: false, - includeIssueTracker: false, - )} +${_headerSection('plugin_example', publishable: false, includeRepository: false, includeIssueTracker: false)} ${_environmentSection()} ${_dependenciesSection()} ${_flutterSection()} @@ -197,8 +200,10 @@ ${_flutterSection()} }); test('passes for a Flutter package following conventions', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); package.pubspecFile.writeAsStringSync(''' ${_headerSection('a_package')} @@ -211,12 +216,7 @@ ${_falseSecretsSection()} '''); package.getExamples().first.pubspecFile.writeAsStringSync(''' -${_headerSection( - 'a_package', - publishable: false, - includeRepository: false, - includeIssueTracker: false, - )} +${_headerSection('a_package', publishable: false, includeRepository: false, includeIssueTracker: false)} ${_environmentSection()} ${_dependenciesSection()} ${_flutterSection()} @@ -237,8 +237,11 @@ ${_flutterSection()} }); test('passes for a minimal package following conventions', () async { - final RepositoryPackage package = - createFakePackage('package', packagesDir, examples: []); + final RepositoryPackage package = createFakePackage( + 'package', + packagesDir, + examples: [], + ); package.pubspecFile.writeAsStringSync(''' ${_headerSection('package')} @@ -261,8 +264,11 @@ ${_topicsSection()} }); test('fails when homepage is included', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin', includeHomepage: true)} @@ -274,23 +280,30 @@ ${_devDependenciesSection()} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - 'Found a "homepage" entry; only "repository" should be used.'), + 'Found a "homepage" entry; only "repository" should be used.', + ), ]), ); }); test('fails when repository is missing', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin', includeRepository: false)} @@ -302,22 +315,26 @@ ${_devDependenciesSection()} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, - containsAllInOrder([ - contains('Missing "repository"'), - ]), + containsAllInOrder([contains('Missing "repository"')]), ); }); test('fails when homepage is given instead of repository', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin', includeHomepage: true, includeRepository: false)} @@ -329,23 +346,30 @@ ${_devDependenciesSection()} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - 'Found a "homepage" entry; only "repository" should be used.'), + 'Found a "homepage" entry; only "repository" should be used.', + ), ]), ); }); test('fails when repository package name is incorrect', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin', repositoryPackagesDirRelativePath: 'different_plugin')} @@ -357,9 +381,12 @@ ${_devDependenciesSection()} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -371,8 +398,11 @@ ${_devDependenciesSection()} }); test('fails when repository uses master instead of main', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin', repositoryBranch: 'master')} @@ -384,23 +414,31 @@ ${_devDependenciesSection()} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ - contains('The "repository" link should start with the repository\'s ' - 'main tree: "https://github.com/flutter/packages/tree/main"'), + contains( + 'The "repository" link should start with the repository\'s ' + 'main tree: "https://github.com/flutter/packages/tree/main"', + ), ]), ); }); test('fails when repository is not flutter/packages', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin', repository: 'flutter/plugins')} @@ -412,23 +450,31 @@ ${_devDependenciesSection()} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ - contains('The "repository" link should start with the repository\'s ' - 'main tree: "https://github.com/flutter/packages/tree/main"'), + contains( + 'The "repository" link should start with the repository\'s ' + 'main tree: "https://github.com/flutter/packages/tree/main"', + ), ]), ); }); test('fails when issue tracker is missing', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin', includeIssueTracker: false)} @@ -440,9 +486,12 @@ ${_devDependenciesSection()} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -455,8 +504,10 @@ ${_devDependenciesSection()} test('fails when description is too short', () async { final RepositoryPackage plugin = createFakePlugin( - 'a_plugin', packagesDir.childDirectory('a_plugin'), - examples: []); + 'a_plugin', + packagesDir.childDirectory('a_plugin'), + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin', description: 'Too short')} @@ -468,27 +519,35 @@ ${_devDependenciesSection()} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ - contains('"description" is too short. pub.dev recommends package ' - 'descriptions of 60-180 characters.'), + contains( + '"description" is too short. pub.dev recommends package ' + 'descriptions of 60-180 characters.', + ), ]), ); }); test( - 'allows short descriptions for non-app-facing parts of federated plugins', - () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + 'allows short descriptions for non-app-facing parts of federated plugins', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); - plugin.pubspecFile.writeAsStringSync(''' + plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin', description: 'Too short')} ${_environmentSection()} ${_flutterSection(isPlugin: true)} @@ -496,27 +555,37 @@ ${_dependenciesSection()} ${_devDependenciesSection()} '''); - Error? commandError; - final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('"description" is too short. pub.dev recommends package ' - 'descriptions of 60-180 characters.'), - ]), - ); - }); + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains( + '"description" is too short. pub.dev recommends package ' + 'descriptions of 60-180 characters.', + ), + ]), + ); + }, + ); test('fails when description is too long', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); - const String description = 'This description is too long. It just goes ' + const description = + 'This description is too long. It just goes ' 'on and on and on and on and on. pub.dev will down-score it because ' 'there is just too much here. Someone shoul really cut this down to just ' 'the core description so that search results are more useful and the ' @@ -531,23 +600,31 @@ ${_devDependenciesSection()} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ - contains('"description" is too long. pub.dev recommends package ' - 'descriptions of 60-180 characters.'), + contains( + '"description" is too long. pub.dev recommends package ' + 'descriptions of 60-180 characters.', + ), ]), ); }); test('fails when topics section is missing', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin')} @@ -559,9 +636,12 @@ ${_devDependenciesSection()} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -573,8 +653,11 @@ ${_devDependenciesSection()} }); test('fails when topics section is empty', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin')} @@ -587,9 +670,12 @@ ${_topicsSection([])} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -600,13 +686,16 @@ ${_topicsSection([])} ); }); - test('fails when federated plugin topics do not include plugin name', - () async { - final RepositoryPackage plugin = createFakePlugin( - 'some_plugin_ios', packagesDir.childDirectory('some_plugin'), - examples: []); + test( + 'fails when federated plugin topics do not include plugin name', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'some_plugin_ios', + packagesDir.childDirectory('some_plugin'), + examples: [], + ); - plugin.pubspecFile.writeAsStringSync(''' + plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin')} ${_environmentSection()} ${_flutterSection(isPlugin: true)} @@ -615,26 +704,34 @@ ${_devDependenciesSection()} ${_topicsSection()} '''); - Error? commandError; - final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains( + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains( 'A federated plugin package should include its plugin name as a topic. ' - 'Add "some-plugin" to the "topics" section.'), - ]), - ); - }); + 'Add "some-plugin" to the "topics" section.', + ), + ]), + ); + }, + ); test('fails when topic name contains a space', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin')} @@ -647,9 +744,12 @@ ${_topicsSection(['plugin a'])} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -661,8 +761,11 @@ ${_topicsSection(['plugin a'])} }); test('fails when topic a topic name contains double dash', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin')} @@ -675,9 +778,12 @@ ${_topicsSection(['plugin--a'])} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -689,8 +795,11 @@ ${_topicsSection(['plugin--a'])} }); test('fails when topic a topic name starts with a number', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin')} @@ -703,9 +812,12 @@ ${_topicsSection(['1plugin-a'])} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -717,8 +829,11 @@ ${_topicsSection(['1plugin-a'])} }); test('fails when topic a topic name contains uppercase', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin')} @@ -731,9 +846,12 @@ ${_topicsSection(['plugin-A'])} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -745,8 +863,11 @@ ${_topicsSection(['plugin-A'])} }); test('fails when there are more than 5 topics', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin')} @@ -754,35 +875,35 @@ ${_environmentSection()} ${_flutterSection(isPlugin: true)} ${_dependenciesSection()} ${_devDependenciesSection()} -${_topicsSection([ - 'plugin-a', - 'plugin-a', - 'plugin-a', - 'plugin-a', - 'plugin-a', - 'plugin-a' - ])} +${_topicsSection(['plugin-a', 'plugin-a', 'plugin-a', 'plugin-a', 'plugin-a', 'plugin-a'])} '''); Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - ' A published package should have maximum 5 topics. See https://dart.dev/tools/pub/pubspec#topics.'), + ' A published package should have maximum 5 topics. See https://dart.dev/tools/pub/pubspec#topics.', + ), ]), ); }); test('fails if a topic name is longer than 32 characters', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin')} @@ -795,23 +916,30 @@ ${_topicsSection(['foobarfoobarfoobarfoobarfoobarfoobarfoo'])} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - 'Invalid topic(s): foobarfoobarfoobarfoobarfoobarfoobarfoo in "topics" section. '), + 'Invalid topic(s): foobarfoobarfoobarfoobarfoobarfoobarfoo in "topics" section. ', + ), ]), ); }); test('fails if a topic name is longer than 2 characters', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin')} @@ -824,9 +952,12 @@ ${_topicsSection(['a'])} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -838,8 +969,11 @@ ${_topicsSection(['a'])} }); test('fails if a topic name ends in a dash', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin')} @@ -852,9 +986,12 @@ ${_topicsSection(['plugin-'])} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -866,8 +1003,11 @@ ${_topicsSection(['plugin-'])} }); test('Invalid topics section has expected error message', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin')} @@ -880,25 +1020,33 @@ ${_topicsSection(['plugin-A', 'Plugin-b'])} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ - contains('Invalid topic(s): plugin-A, Plugin-b in "topics" section. ' - 'Topics must consist of lowercase alphanumerical characters or dash (but no double dash), ' - 'start with a-z and ending with a-z or 0-9, have a minimum of 2 characters ' - 'and have a maximum of 32 characters.'), + contains( + 'Invalid topic(s): plugin-A, Plugin-b in "topics" section. ' + 'Topics must consist of lowercase alphanumerical characters or dash (but no double dash), ' + 'start with a-z and ending with a-z or 0-9, have a minimum of 2 characters ' + 'and have a maximum of 32 characters.', + ), ]), ); }); test('fails when environment section is out of order', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin')} @@ -910,23 +1058,30 @@ ${_environmentSection()} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - 'Major sections should follow standard repository ordering:'), + 'Major sections should follow standard repository ordering:', + ), ]), ); }); test('fails when flutter section is out of order', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin')} @@ -938,23 +1093,30 @@ ${_devDependenciesSection()} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - 'Major sections should follow standard repository ordering:'), + 'Major sections should follow standard repository ordering:', + ), ]), ); }); test('fails when dependencies section is out of order', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin')} @@ -966,16 +1128,20 @@ ${_dependenciesSection()} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - 'Major sections should follow standard repository ordering:'), + 'Major sections should follow standard repository ordering:', + ), ]), ); }); @@ -993,23 +1159,30 @@ ${_dependenciesSection()} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - 'Major sections should follow standard repository ordering:'), + 'Major sections should follow standard repository ordering:', + ), ]), ); }); test('fails when false_secrets section is out of order', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin')} @@ -1023,27 +1196,34 @@ ${_topicsSection()} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - 'Major sections should follow standard repository ordering:'), + 'Major sections should follow standard repository ordering:', + ), ]), ); }); - test('fails when an implemenation package is missing "implements"', - () async { - final RepositoryPackage plugin = createFakePlugin( - 'plugin_a_foo', packagesDir.childDirectory('plugin_a'), - examples: []); + test( + 'fails when an implemenation package is missing "implements"', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin_a_foo', + packagesDir.childDirectory('plugin_a'), + examples: [], + ); - plugin.pubspecFile.writeAsStringSync(''' + plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin_a_foo')} ${_environmentSection()} ${_flutterSection(isPlugin: true)} @@ -1052,28 +1232,35 @@ ${_devDependenciesSection()} ${_topicsSection()} '''); - Error? commandError; - final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('Missing "implements: plugin_a" in "plugin" section.'), - ]), - ); - }); + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains('Missing "implements: plugin_a" in "plugin" section.'), + ]), + ); + }, + ); - test('fails when an implemenation package has the wrong "implements"', - () async { - final RepositoryPackage plugin = createFakePlugin( - 'plugin_a_foo', packagesDir.childDirectory('plugin_a'), - examples: []); + test( + 'fails when an implemenation package has the wrong "implements"', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin_a_foo', + packagesDir.childDirectory('plugin_a'), + examples: [], + ); - plugin.pubspecFile.writeAsStringSync(''' + plugin.pubspecFile.writeAsStringSync(''' ${_headerSection('plugin_a_foo')} ${_environmentSection()} ${_flutterSection(isPlugin: true, implementedPackage: 'plugin_a_foo')} @@ -1082,32 +1269,37 @@ ${_devDependenciesSection()} ${_topicsSection()} '''); - Error? commandError; - final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('Expecetd "implements: plugin_a"; ' - 'found "implements: plugin_a_foo".'), - ]), - ); - }); + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains( + 'Expecetd "implements: plugin_a"; ' + 'found "implements: plugin_a_foo".', + ), + ]), + ); + }, + ); test('passes for a correct implemenation package', () async { final RepositoryPackage plugin = createFakePlugin( - 'plugin_a_foo', packagesDir.childDirectory('plugin_a'), - examples: []); + 'plugin_a_foo', + packagesDir.childDirectory('plugin_a'), + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' -${_headerSection( - 'plugin_a_foo', - repositoryPackagesDirRelativePath: 'plugin_a/plugin_a_foo', - )} +${_headerSection('plugin_a_foo', repositoryPackagesDirRelativePath: 'plugin_a/plugin_a_foo')} ${_environmentSection()} ${_flutterSection(isPlugin: true, implementedPackage: 'plugin_a')} ${_dependenciesSection()} @@ -1115,8 +1307,9 @@ ${_devDependenciesSection()} ${_topicsSection(['plugin-a'])} '''); - final List output = - await runCapturingPrint(runner, ['pubspec-check']); + final List output = await runCapturingPrint(runner, [ + 'pubspec-check', + ]); expect( output, @@ -1129,21 +1322,17 @@ ${_topicsSection(['plugin-a'])} test('fails when a "default_package" looks incorrect', () async { final RepositoryPackage plugin = createFakePlugin( - 'plugin_a', packagesDir.childDirectory('plugin_a'), - examples: []); + 'plugin_a', + packagesDir.childDirectory('plugin_a'), + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' -${_headerSection( - 'plugin_a', - repositoryPackagesDirRelativePath: 'plugin_a/plugin_a', - )} +${_headerSection('plugin_a', repositoryPackagesDirRelativePath: 'plugin_a/plugin_a')} ${_environmentSection()} -${_flutterSection( - isPlugin: true, - pluginPlatformDetails: >{ - 'android': {'default_package': 'plugin_b_android'} - }, - )} +${_flutterSection(isPlugin: true, pluginPlatformDetails: >{ + 'android': {'default_package': 'plugin_b_android'}, + })} ${_dependenciesSection()} ${_devDependenciesSection()} ${_topicsSection()} @@ -1151,70 +1340,75 @@ ${_topicsSection()} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - '"plugin_b_android" is not an expected implementation name for "plugin_a"'), + '"plugin_b_android" is not an expected implementation name for "plugin_a"', + ), ]), ); }); test( - 'fails when a "default_package" does not have a corresponding dependency', - () async { - final RepositoryPackage plugin = createFakePlugin( - 'plugin_a', packagesDir.childDirectory('plugin_a'), - examples: []); + 'fails when a "default_package" does not have a corresponding dependency', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin_a', + packagesDir.childDirectory('plugin_a'), + examples: [], + ); - plugin.pubspecFile.writeAsStringSync(''' -${_headerSection( - 'plugin_a', - repositoryPackagesDirRelativePath: 'plugin_a/plugin_a', - )} + plugin.pubspecFile.writeAsStringSync(''' +${_headerSection('plugin_a', repositoryPackagesDirRelativePath: 'plugin_a/plugin_a')} ${_environmentSection()} -${_flutterSection( - isPlugin: true, - pluginPlatformDetails: >{ - 'android': {'default_package': 'plugin_a_android'} - }, - )} +${_flutterSection(isPlugin: true, pluginPlatformDetails: >{ + 'android': {'default_package': 'plugin_a_android'}, + })} ${_dependenciesSection()} ${_devDependenciesSection()} ${_topicsSection()} '''); - Error? commandError; - final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('The following default_packages are missing corresponding ' - 'dependencies:\n plugin_a_android'), - ]), - ); - }); + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains( + 'The following default_packages are missing corresponding ' + 'dependencies:\n plugin_a_android', + ), + ]), + ); + }, + ); test('passes for an app-facing package without "implements"', () async { final RepositoryPackage plugin = createFakePlugin( - 'plugin_a', packagesDir.childDirectory('plugin_a'), - examples: []); + 'plugin_a', + packagesDir.childDirectory('plugin_a'), + examples: [], + ); plugin.pubspecFile.writeAsStringSync(''' -${_headerSection( - 'plugin_a', - repositoryPackagesDirRelativePath: 'plugin_a/plugin_a', - )} +${_headerSection('plugin_a', repositoryPackagesDirRelativePath: 'plugin_a/plugin_a')} ${_environmentSection()} ${_flutterSection(isPlugin: true)} ${_dependenciesSection()} @@ -1222,8 +1416,9 @@ ${_devDependenciesSection()} ${_topicsSection(['plugin-a'])} '''); - final List output = - await runCapturingPrint(runner, ['pubspec-check']); + final List output = await runCapturingPrint(runner, [ + 'pubspec-check', + ]); expect( output, @@ -1234,18 +1429,17 @@ ${_topicsSection(['plugin-a'])} ); }); - test('passes for a platform interface package without "implements"', - () async { - final RepositoryPackage plugin = createFakePlugin( - 'plugin_a_platform_interface', packagesDir.childDirectory('plugin_a'), - examples: []); + test( + 'passes for a platform interface package without "implements"', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin_a_platform_interface', + packagesDir.childDirectory('plugin_a'), + examples: [], + ); - plugin.pubspecFile.writeAsStringSync(''' -${_headerSection( - 'plugin_a_platform_interface', - repositoryPackagesDirRelativePath: - 'plugin_a/plugin_a_platform_interface', - )} + plugin.pubspecFile.writeAsStringSync(''' +${_headerSection('plugin_a_platform_interface', repositoryPackagesDirRelativePath: 'plugin_a/plugin_a_platform_interface')} ${_environmentSection()} ${_flutterSection(isPlugin: true)} ${_dependenciesSection()} @@ -1253,22 +1447,26 @@ ${_devDependenciesSection()} ${_topicsSection(['plugin-a'])} '''); - final List output = - await runCapturingPrint(runner, ['pubspec-check']); + final List output = await runCapturingPrint(runner, [ + 'pubspec-check', + ]); - expect( - output, - containsAllInOrder([ - contains('Running for plugin_a_platform_interface...'), - contains('No issues found!'), - ]), - ); - }); + expect( + output, + containsAllInOrder([ + contains('Running for plugin_a_platform_interface...'), + contains('No issues found!'), + ]), + ); + }, + ); test('validates some properties even for unpublished packages', () async { final RepositoryPackage plugin = createFakePlugin( - 'plugin_a_foo', packagesDir.childDirectory('plugin_a'), - examples: []); + 'plugin_a_foo', + packagesDir.childDirectory('plugin_a'), + examples: [], + ); // Environment section is in the wrong location. // Missing 'implements'. @@ -1282,42 +1480,45 @@ ${_environmentSection()} Error? commandError; final List output = await runCapturingPrint( - runner, ['pubspec-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - 'Major sections should follow standard repository ordering:'), + 'Major sections should follow standard repository ordering:', + ), contains('Missing "implements: plugin_a" in "plugin" section.'), ]), ); }); test('ignores some checks for unpublished packages', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, examples: []); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + examples: [], + ); // Missing metadata that is only useful for published packages, such as // repository and issue tracker. plugin.pubspecFile.writeAsStringSync(''' -${_headerSection( - 'plugin', - publishable: false, - includeRepository: false, - includeIssueTracker: false, - )} +${_headerSection('plugin', publishable: false, includeRepository: false, includeIssueTracker: false)} ${_environmentSection()} ${_flutterSection(isPlugin: true)} ${_dependenciesSection()} ${_devDependenciesSection()} '''); - final List output = - await runCapturingPrint(runner, ['pubspec-check']); + final List output = await runCapturingPrint(runner, [ + 'pubspec-check', + ]); expect( output, @@ -1328,174 +1529,217 @@ ${_devDependenciesSection()} ); }); - test('fails when a Flutter package has a too-low minimum Flutter version', - () async { - final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - isFlutter: true, examples: []); + test( + 'fails when a Flutter package has a too-low minimum Flutter version', + () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + isFlutter: true, + examples: [], + ); - package.pubspecFile.writeAsStringSync(''' + package.pubspecFile.writeAsStringSync(''' ${_headerSection('a_package')} ${_environmentSection(flutterConstraint: '>=2.10.0')} ${_dependenciesSection()} ${_topicsSection()} '''); - Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'pubspec-check', - '--min-min-flutter-version', - '3.0.0' - ], errorHandler: (Error e) { - commandError = e; - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['pubspec-check', '--min-min-flutter-version', '3.0.0'], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('Minimum allowed Flutter version 2.10.0 is less than 3.0.0'), - ]), - ); - }); + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains( + 'Minimum allowed Flutter version 2.10.0 is less than 3.0.0', + ), + ]), + ); + }, + ); test( - 'passes when a Flutter package requires exactly the minimum Flutter version', - () async { - final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - isFlutter: true, examples: []); + 'passes when a Flutter package requires exactly the minimum Flutter version', + () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + isFlutter: true, + examples: [], + ); - package.pubspecFile.writeAsStringSync(''' + package.pubspecFile.writeAsStringSync(''' ${_headerSection('a_package')} ${_environmentSection(flutterConstraint: '>=3.3.0', dartConstraint: '>=2.18.0 <4.0.0')} ${_dependenciesSection()} ${_topicsSection()} '''); - final List output = await runCapturingPrint(runner, - ['pubspec-check', '--min-min-flutter-version', '3.3.0']); + final List output = await runCapturingPrint(runner, [ + 'pubspec-check', + '--min-min-flutter-version', + '3.3.0', + ]); - expect( - output, - containsAllInOrder([ - contains('Running for a_package...'), - contains('No issues found!'), - ]), - ); - }); + expect( + output, + containsAllInOrder([ + contains('Running for a_package...'), + contains('No issues found!'), + ]), + ); + }, + ); test( - 'passes when a Flutter package requires a higher minimum Flutter version', - () async { - final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - isFlutter: true, examples: []); + 'passes when a Flutter package requires a higher minimum Flutter version', + () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + isFlutter: true, + examples: [], + ); - package.pubspecFile.writeAsStringSync(''' + package.pubspecFile.writeAsStringSync(''' ${_headerSection('a_package')} ${_environmentSection(flutterConstraint: '>=3.7.0', dartConstraint: '>=2.19.0 <4.0.0')} ${_dependenciesSection()} ${_topicsSection()} '''); - final List output = await runCapturingPrint(runner, - ['pubspec-check', '--min-min-flutter-version', '3.3.0']); + final List output = await runCapturingPrint(runner, [ + 'pubspec-check', + '--min-min-flutter-version', + '3.3.0', + ]); - expect( - output, - containsAllInOrder([ - contains('Running for a_package...'), - contains('No issues found!'), - ]), - ); - }); + expect( + output, + containsAllInOrder([ + contains('Running for a_package...'), + contains('No issues found!'), + ]), + ); + }, + ); - test('fails when a non-Flutter package has a too-low minimum Dart version', - () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, examples: []); + test( + 'fails when a non-Flutter package has a too-low minimum Dart version', + () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + examples: [], + ); - package.pubspecFile.writeAsStringSync(''' + package.pubspecFile.writeAsStringSync(''' ${_headerSection('a_package')} ${_environmentSection(dartConstraint: '>=2.14.0 <4.0.0', flutterConstraint: null)} ${_dependenciesSection()} ${_topicsSection()} '''); - Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'pubspec-check', - '--min-min-flutter-version', - '3.0.0' - ], errorHandler: (Error e) { - commandError = e; - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['pubspec-check', '--min-min-flutter-version', '3.0.0'], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('Minimum allowed Dart version 2.14.0 is less than 2.17.0'), - ]), - ); - }); + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains('Minimum allowed Dart version 2.14.0 is less than 2.17.0'), + ]), + ); + }, + ); test( - 'passes when a non-Flutter package requires exactly the minimum Dart version', - () async { - final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - isFlutter: true, examples: []); + 'passes when a non-Flutter package requires exactly the minimum Dart version', + () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + isFlutter: true, + examples: [], + ); - package.pubspecFile.writeAsStringSync(''' + package.pubspecFile.writeAsStringSync(''' ${_headerSection('a_package')} ${_environmentSection(dartConstraint: '>=2.18.0 <4.0.0', flutterConstraint: null)} ${_dependenciesSection()} ${_topicsSection()} '''); - final List output = await runCapturingPrint(runner, - ['pubspec-check', '--min-min-flutter-version', '3.3.0']); + final List output = await runCapturingPrint(runner, [ + 'pubspec-check', + '--min-min-flutter-version', + '3.3.0', + ]); - expect( - output, - containsAllInOrder([ - contains('Running for a_package...'), - contains('No issues found!'), - ]), - ); - }); + expect( + output, + containsAllInOrder([ + contains('Running for a_package...'), + contains('No issues found!'), + ]), + ); + }, + ); test( - 'passes when a non-Flutter package requires a higher minimum Dart version', - () async { - final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - isFlutter: true, examples: []); + 'passes when a non-Flutter package requires a higher minimum Dart version', + () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + isFlutter: true, + examples: [], + ); - package.pubspecFile.writeAsStringSync(''' + package.pubspecFile.writeAsStringSync(''' ${_headerSection('a_package')} ${_environmentSection(dartConstraint: '>=2.18.0 <4.0.0', flutterConstraint: null)} ${_dependenciesSection()} ${_topicsSection()} '''); - final List output = await runCapturingPrint(runner, - ['pubspec-check', '--min-min-flutter-version', '3.0.0']); + final List output = await runCapturingPrint(runner, [ + 'pubspec-check', + '--min-min-flutter-version', + '3.0.0', + ]); - expect( - output, - containsAllInOrder([ - contains('Running for a_package...'), - contains('No issues found!'), - ]), - ); - }); + expect( + output, + containsAllInOrder([ + contains('Running for a_package...'), + contains('No issues found!'), + ]), + ); + }, + ); test('fails when a Flutter->Dart SDK version mapping is missing', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, examples: []); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + examples: [], + ); package.pubspecFile.writeAsStringSync(''' ${_headerSection('a_package')} @@ -1505,13 +1749,13 @@ ${_topicsSection()} '''); Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'pubspec-check', - '--min-min-flutter-version', - '2.0.0' - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['pubspec-check', '--min-min-flutter-version', '2.0.0'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -1522,12 +1766,14 @@ ${_topicsSection()} ); }); - test( - 'fails when a Flutter package has a too-low minimum Dart version for ' + test('fails when a Flutter package has a too-low minimum Dart version for ' 'the corresponding minimum Flutter version', () async { final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - isFlutter: true, examples: []); + 'a_package', + packagesDir, + isFlutter: true, + examples: [], + ); package.pubspecFile.writeAsStringSync(''' ${_headerSection('a_package')} @@ -1537,30 +1783,38 @@ ${_topicsSection()} '''); Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'pubspec-check', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ - contains('The minimum Dart version is 2.16.0, but the ' - 'minimum Flutter version of 3.3.0 shipped with ' - 'Dart 2.18.0. Please use consistent lower SDK ' - 'bounds'), + contains( + 'The minimum Dart version is 2.16.0, but the ' + 'minimum Flutter version of 3.3.0 shipped with ' + 'Dart 2.18.0. Please use consistent lower SDK ' + 'bounds', + ), ]), ); }); group('dependency check', () { test('passes for local dependencies', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); - final RepositoryPackage dependencyPackage = - createFakePackage('local_dependency', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); + final RepositoryPackage dependencyPackage = createFakePackage( + 'local_dependency', + packagesDir, + ); package.pubspecFile.writeAsStringSync(''' ${_headerSection('a_package')} @@ -1575,8 +1829,9 @@ ${_dependenciesSection()} ${_topicsSection()} '''); - final List output = - await runCapturingPrint(runner, ['pubspec-check']); + final List output = await runCapturingPrint(runner, [ + 'pubspec-check', + ]); expect( output, @@ -1588,8 +1843,11 @@ ${_topicsSection()} }); test('fails when an unexpected dependency is found', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, examples: []); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + examples: [], + ); package.pubspecFile.writeAsStringSync(''' ${_headerSection('a_package')} @@ -1599,28 +1857,34 @@ ${_topicsSection()} '''); Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'pubspec-check', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - ' The following unexpected non-local dependencies were found:\n' - ' bad_dependency\n' - ' Please see https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#Dependencies\n' - ' for more information and next steps.'), + ' The following unexpected non-local dependencies were found:\n' + ' bad_dependency\n' + ' Please see https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#Dependencies\n' + ' for more information and next steps.', + ), ]), ); }); test('fails when an unexpected dev dependency is found', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, examples: []); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + examples: [], + ); package.pubspecFile.writeAsStringSync(''' ${_headerSection('a_package')} @@ -1631,28 +1895,33 @@ ${_topicsSection()} '''); Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'pubspec-check', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - ' The following unexpected non-local dependencies were found:\n' - ' bad_dependency\n' - ' Please see https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#Dependencies\n' - ' for more information and next steps.'), + ' The following unexpected non-local dependencies were found:\n' + ' bad_dependency\n' + ' Please see https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#Dependencies\n' + ' for more information and next steps.', + ), ]), ); }); test('passes when a dependency is on the allow list', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); package.pubspecFile.writeAsStringSync(''' ${_headerSection('a_package')} @@ -1661,8 +1930,11 @@ ${_dependenciesSection(['allowed: ^1.0.0'])} ${_topicsSection()} '''); - final List output = await runCapturingPrint(runner, - ['pubspec-check', '--allow-dependencies', 'allowed']); + final List output = await runCapturingPrint(runner, [ + 'pubspec-check', + '--allow-dependencies', + 'allowed', + ]); expect( output, @@ -1674,65 +1946,72 @@ ${_topicsSection()} }); test( - 'passes when an exactly-pinned dependency is on the pinned allow list', - () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + 'passes when an exactly-pinned dependency is on the pinned allow list', + () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); - package.pubspecFile.writeAsStringSync(''' + package.pubspecFile.writeAsStringSync(''' ${_headerSection('a_package')} ${_environmentSection()} ${_dependenciesSection(['allow_pinned: 1.0.0'])} ${_topicsSection()} '''); - final List output = await runCapturingPrint(runner, [ - 'pubspec-check', - '--allow-pinned-dependencies', - 'allow_pinned' - ]); - - expect( - output, - containsAllInOrder([ - contains('Running for a_package...'), - contains('No issues found!'), - ]), - ); - }); + final List output = await runCapturingPrint(runner, [ + 'pubspec-check', + '--allow-pinned-dependencies', + 'allow_pinned', + ]); + + expect( + output, + containsAllInOrder([ + contains('Running for a_package...'), + contains('No issues found!'), + ]), + ); + }, + ); test( - 'passes when an explicit-range-pinned dependency is on the pinned allow list', - () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + 'passes when an explicit-range-pinned dependency is on the pinned allow list', + () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); - package.pubspecFile.writeAsStringSync(''' + package.pubspecFile.writeAsStringSync(''' ${_headerSection('a_package')} ${_environmentSection()} ${_dependenciesSection(['allow_pinned: ">=1.0.0 <=1.3.1"'])} ${_topicsSection()} '''); - final List output = await runCapturingPrint(runner, [ - 'pubspec-check', - '--allow-pinned-dependencies', - 'allow_pinned' - ]); + final List output = await runCapturingPrint(runner, [ + 'pubspec-check', + '--allow-pinned-dependencies', + 'allow_pinned', + ]); + + expect( + output, + containsAllInOrder([ + contains('Running for a_package...'), + contains('No issues found!'), + ]), + ); + }, + ); - expect( - output, - containsAllInOrder([ - contains('Running for a_package...'), - contains('No issues found!'), - ]), + test('fails when an allowed-when-pinned dependency is unpinned', () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, ); - }); - - test('fails when an allowed-when-pinned dependency is unpinned', - () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); package.pubspecFile.writeAsStringSync(''' ${_headerSection('a_package')} @@ -1742,29 +2021,34 @@ ${_topicsSection()} '''); Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'pubspec-check', - '--allow-pinned-dependencies', - 'allow_pinned' - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + [ + 'pubspec-check', + '--allow-pinned-dependencies', + 'allow_pinned', + ], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - ' The following unexpected non-local dependencies were found:\n' - ' allow_pinned\n' - ' Please see https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#Dependencies\n' - ' for more information and next steps.'), + ' The following unexpected non-local dependencies were found:\n' + ' allow_pinned\n' + ' Please see https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#Dependencies\n' + ' for more information and next steps.', + ), ]), ); }); group('dev dependencies', () { - const List packages = [ + const packages = [ 'build_runner', 'integration_test', 'flutter_test', @@ -1773,43 +2057,44 @@ ${_topicsSection()} 'pigeon', 'test', ]; - for (final String dependency in packages) { - test('fails when $dependency is used in non dev dependency', - () async { + for (final dependency in packages) { + test('fails when $dependency is used in non dev dependency', () async { final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - examples: []); + 'a_package', + packagesDir, + examples: [], + ); - final String version = + final version = dependency == 'integration_test' || dependency == 'flutter_test' - ? '{ sdk: flutter }' - : '1.0.0'; + ? '{ sdk: flutter }' + : '1.0.0'; package.pubspecFile.writeAsStringSync(''' ${_headerSection('a_package')} ${_environmentSection()} -${_dependenciesSection([ - '$dependency: $version', - ])} +${_dependenciesSection(['$dependency: $version'])} ${_devDependenciesSection()} ${_topicsSection()} '''); Error? commandError; - final List output = - await runCapturingPrint(runner, [ - 'pubspec-check', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['pubspec-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - ' The following dev dependencies were found in the dependencies section:\n' - ' $dependency\n' - ' Please move them to dev_dependencies.'), + ' The following dev dependencies were found in the dependencies section:\n' + ' $dependency\n' + ' Please move them to dev_dependencies.', + ), ]), ); }); @@ -1817,34 +2102,35 @@ ${_topicsSection()} }); test( - 'passes when integration_test or flutter_test are used in non published package', - () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, examples: []); + 'passes when integration_test or flutter_test are used in non published package', + () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + examples: [], + ); - package.pubspecFile.writeAsStringSync(''' + package.pubspecFile.writeAsStringSync(''' ${_headerSection('a_package', publishable: false)} ${_environmentSection()} -${_dependenciesSection([ - 'integration_test: \n sdk: flutter', - 'flutter_test: \n sdk: flutter' - ])} +${_dependenciesSection(['integration_test: \n sdk: flutter', 'flutter_test: \n sdk: flutter'])} ${_devDependenciesSection()} ${_topicsSection()} '''); - final List output = await runCapturingPrint(runner, [ - 'pubspec-check', - ]); - - expect( - output, - containsAllInOrder([ - contains('Running for a_package...'), - contains('Ran for'), - ]), - ); - }); + final List output = await runCapturingPrint(runner, [ + 'pubspec-check', + ]); + + expect( + output, + containsAllInOrder([ + contains('Running for a_package...'), + contains('Ran for'), + ]), + ); + }, + ); }); }); @@ -1859,7 +2145,7 @@ ${_topicsSection()} final GitDir gitDir; (:packagesDir, :processRunner, gitProcessRunner: _, :gitDir) = configureBaseCommandMocks(platform: mockPlatform); - final PubspecCheckCommand command = PubspecCheckCommand( + final command = PubspecCheckCommand( packagesDir, processRunner: processRunner, platform: mockPlatform, @@ -1867,13 +2153,18 @@ ${_topicsSection()} ); runner = CommandRunner( - 'pubspec_check_command', 'Test for pubspec_check_command'); + 'pubspec_check_command', + 'Test for pubspec_check_command', + ); runner.addCommand(command); }); test('repository check works', () async { - final RepositoryPackage package = - createFakePackage('package', packagesDir, examples: []); + final RepositoryPackage package = createFakePackage( + 'package', + packagesDir, + examples: [], + ); package.pubspecFile.writeAsStringSync(''' ${_headerSection('package')} @@ -1882,8 +2173,9 @@ ${_dependenciesSection()} ${_topicsSection()} '''); - final List output = - await runCapturingPrint(runner, ['pubspec-check']); + final List output = await runCapturingPrint(runner, [ + 'pubspec-check', + ]); expect( output, diff --git a/script/tool/test/readme_check_command_test.dart b/script/tool/test/readme_check_command_test.dart index 76ec2472ab51..7ee704a11af8 100644 --- a/script/tool/test/readme_check_command_test.dart +++ b/script/tool/test/readme_check_command_test.dart @@ -24,7 +24,7 @@ void main() { final GitDir gitDir; (:packagesDir, :processRunner, gitProcessRunner: _, :gitDir) = configureBaseCommandMocks(platform: mockPlatform); - final ReadmeCheckCommand command = ReadmeCheckCommand( + final command = ReadmeCheckCommand( packagesDir, processRunner: processRunner, platform: mockPlatform, @@ -32,21 +32,26 @@ void main() { ); runner = CommandRunner( - 'readme_check_command', 'Test for readme_check_command'); + 'readme_check_command', + 'Test for readme_check_command', + ); runner.addCommand(command); }); test('prints paths of checked READMEs', () async { final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - examples: ['example1', 'example2']); + 'a_package', + packagesDir, + examples: ['example1', 'example2'], + ); for (final RepositoryPackage example in package.getExamples()) { example.readmeFile.writeAsStringSync('A readme'); } getExampleDir(package).childFile('README.md').writeAsStringSync('A readme'); - final List output = - await runCapturingPrint(runner, ['readme-check']); + final List output = await runCapturingPrint(runner, [ + 'readme-check', + ]); expect( output, @@ -60,49 +65,56 @@ void main() { }); test('fails when package README is missing', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); package.readmeFile.deleteSync(); Error? commandError; final List output = await runCapturingPrint( - runner, ['readme-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['readme-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, - containsAllInOrder([ - contains('Missing README.md'), - ]), + containsAllInOrder([contains('Missing README.md')]), ); }); test('passes when example README is missing', () async { createFakePackage('a_package', packagesDir); - final List output = - await runCapturingPrint(runner, ['readme-check']); + final List output = await runCapturingPrint(runner, [ + 'readme-check', + ]); expect( output, - containsAllInOrder([ - contains('No README for example'), - ]), + containsAllInOrder([contains('No README for example')]), ); }); test('does not inculde non-example subpackages', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); - const String subpackageName = 'special_test'; - final RepositoryPackage miscSubpackage = - createFakePackage(subpackageName, package.directory); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); + const subpackageName = 'special_test'; + final RepositoryPackage miscSubpackage = createFakePackage( + subpackageName, + package.directory, + ); miscSubpackage.readmeFile.deleteSync(); - final List output = - await runCapturingPrint(runner, ['readme-check']); + final List output = await runCapturingPrint(runner, [ + 'readme-check', + ]); expect(output, isNot(contains(subpackageName))); }); @@ -124,26 +136,34 @@ samples, guidance on mobile development, and a full API reference. Error? commandError; final List output = await runCapturingPrint( - runner, ['readme-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['readme-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ - contains('The boilerplate section about getting started with Flutter ' - 'should not be left in.'), + contains( + 'The boilerplate section about getting started with Flutter ' + 'should not be left in.', + ), contains('Contains template boilerplate'), ]), ); }); - test('fails when example README still has application template boilerplate', - () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); - package.getExamples().first.readmeFile.writeAsStringSync(''' + test( + 'fails when example README still has application template boilerplate', + () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); + package.getExamples().first.readmeFile.writeAsStringSync(''' ## Getting Started This project is a starting point for a Flutter application. @@ -158,28 +178,35 @@ For help getting started with Flutter development, view the samples, guidance on mobile development, and a full API reference. '''); - Error? commandError; - final List output = await runCapturingPrint( - runner, ['readme-check'], errorHandler: (Error e) { - commandError = e; - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['readme-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('The boilerplate section about getting started with Flutter ' - 'should not be left in.'), - contains('Contains template boilerplate'), - ]), - ); - }); + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains( + 'The boilerplate section about getting started with Flutter ' + 'should not be left in.', + ), + contains('Contains template boilerplate'), + ]), + ); + }, + ); - test( - 'fails when a plugin implementation package example README has the ' + test('fails when a plugin implementation package example README has the ' 'template boilerplate', () async { final RepositoryPackage package = createFakePlugin( - 'a_plugin_ios', packagesDir.childDirectory('a_plugin')); + 'a_plugin_ios', + packagesDir.childDirectory('a_plugin'), + ); package.getExamples().first.readmeFile.writeAsStringSync(''' # a_plugin_ios_example @@ -188,23 +215,27 @@ Demonstrates how to use the a_plugin_ios plugin. Error? commandError; final List output = await runCapturingPrint( - runner, ['readme-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['readme-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ - contains('The boilerplate should not be left in for a federated plugin ' - "implementation package's example."), + contains( + 'The boilerplate should not be left in for a federated plugin ' + "implementation package's example.", + ), contains('Contains template boilerplate'), ]), ); }); - test( - 'allows the template boilerplate in the example README for packages ' + test('allows the template boilerplate in the example README for packages ' 'other than plugin implementation packages', () async { final RepositoryPackage package = createFakePlugin( 'a_plugin', @@ -230,8 +261,9 @@ A great plugin. Demonstrates how to use the a_plugin plugin. '''); - final List output = - await runCapturingPrint(runner, ['readme-check']); + final List output = await runCapturingPrint(runner, [ + 'readme-check', + ]); expect( output, @@ -243,47 +275,57 @@ Demonstrates how to use the a_plugin plugin. }); test( - 'fails when a plugin implementation package example README does not have ' - 'the repo-standard message', () async { - final RepositoryPackage package = createFakePlugin( - 'a_plugin_ios', packagesDir.childDirectory('a_plugin')); - package.getExamples().first.readmeFile.writeAsStringSync(''' + 'fails when a plugin implementation package example README does not have ' + 'the repo-standard message', + () async { + final RepositoryPackage package = createFakePlugin( + 'a_plugin_ios', + packagesDir.childDirectory('a_plugin'), + ); + package.getExamples().first.readmeFile.writeAsStringSync(''' # a_plugin_ios_example Some random description. '''); - Error? commandError; - final List output = await runCapturingPrint( - runner, ['readme-check'], errorHandler: (Error e) { - commandError = e; - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['readme-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('The example README for a platform implementation package ' + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains( + 'The example README for a platform implementation package ' 'should warn readers about its intended use. Please copy the ' 'example README from another implementation package in this ' - 'repository.'), - contains('Missing implementation package example warning'), - ]), - ); - }); + 'repository.', + ), + contains('Missing implementation package example warning'), + ]), + ); + }, + ); - test('passes for a plugin implementation package with the expected content', - () async { - final RepositoryPackage package = createFakePlugin( - 'a_plugin', - packagesDir.childDirectory('a_plugin'), - platformSupport: { - platformAndroid: const PlatformDetails(PlatformSupport.inline), - }, - ); - // Write a README with an OS support table so that the main README check - // passes. - package.readmeFile.writeAsStringSync(''' + test( + 'passes for a plugin implementation package with the expected content', + () async { + final RepositoryPackage package = createFakePlugin( + 'a_plugin', + packagesDir.childDirectory('a_plugin'), + platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline), + }, + ); + // Write a README with an OS support table so that the main README check + // passes. + package.readmeFile.writeAsStringSync(''' # a_plugin | | Android | @@ -292,7 +334,7 @@ Some random description. A great plugin. '''); - package.getExamples().first.readmeFile.writeAsStringSync(''' + package.getExamples().first.readmeFile.writeAsStringSync(''' # Platform Implementation Test App This is a test app for manual testing and automated integration testing @@ -304,24 +346,27 @@ Unless you are making changes to this implementation package, this example is very unlikely to be relevant. '''); - final List output = - await runCapturingPrint(runner, ['readme-check']); + final List output = await runCapturingPrint(runner, [ + 'readme-check', + ]); - expect( - output, - containsAll([ - contains(' Checking README.md...'), - contains(' Checking example/README.md...'), - ]), - ); - }); + expect( + output, + containsAll([ + contains(' Checking README.md...'), + contains(' Checking example/README.md...'), + ]), + ); + }, + ); - test( - 'fails when multi-example top-level example directory README still has ' + test('fails when multi-example top-level example directory README still has ' 'application template boilerplate', () async { final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - examples: ['example1', 'example2']); + 'a_package', + packagesDir, + examples: ['example1', 'example2'], + ); package.directory .childDirectory('example') .childFile('README.md') @@ -342,16 +387,21 @@ samples, guidance on mobile development, and a full API reference. Error? commandError; final List output = await runCapturingPrint( - runner, ['readme-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['readme-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ - contains('The boilerplate section about getting started with Flutter ' - 'should not be left in.'), + contains( + 'The boilerplate section about getting started with Flutter ' + 'should not be left in.', + ), contains('Contains template boilerplate'), ]), ); @@ -359,75 +409,86 @@ samples, guidance on mobile development, and a full API reference. group('plugin OS support', () { test( - 'does not check support table for anything other than app-facing plugin packages', - () async { - const String federatedPluginName = 'a_federated_plugin'; - final Directory federatedDir = - packagesDir.childDirectory(federatedPluginName); - // A non-plugin package. - createFakePackage('a_package', packagesDir); - // Non-app-facing parts of a federated plugin. - createFakePlugin( - '${federatedPluginName}_platform_interface', federatedDir); - createFakePlugin('${federatedPluginName}_android', federatedDir); - - final List output = await runCapturingPrint(runner, [ - 'readme-check', - ]); - - expect( - output, - containsAll([ - contains('Running for a_package...'), - contains('Running for a_federated_plugin_platform_interface...'), - contains('Running for a_federated_plugin_android...'), - contains('No issues found!'), - ]), - ); - }); - - test('fails when non-federated plugin is missing an OS support table', - () async { - createFakePlugin('a_plugin', packagesDir); + 'does not check support table for anything other than app-facing plugin packages', + () async { + const federatedPluginName = 'a_federated_plugin'; + final Directory federatedDir = packagesDir.childDirectory( + federatedPluginName, + ); + // A non-plugin package. + createFakePackage('a_package', packagesDir); + // Non-app-facing parts of a federated plugin. + createFakePlugin( + '${federatedPluginName}_platform_interface', + federatedDir, + ); + createFakePlugin('${federatedPluginName}_android', federatedDir); + + final List output = await runCapturingPrint(runner, [ + 'readme-check', + ]); + + expect( + output, + containsAll([ + contains('Running for a_package...'), + contains('Running for a_federated_plugin_platform_interface...'), + contains('Running for a_federated_plugin_android...'), + contains('No issues found!'), + ]), + ); + }, + ); - Error? commandError; - final List output = await runCapturingPrint( - runner, ['readme-check'], errorHandler: (Error e) { - commandError = e; - }); + test( + 'fails when non-federated plugin is missing an OS support table', + () async { + createFakePlugin('a_plugin', packagesDir); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('No OS support table found'), - ]), - ); - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['readme-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); + + expect(commandError, isA()); + expect( + output, + containsAllInOrder([contains('No OS support table found')]), + ); + }, + ); test( - 'fails when app-facing part of a federated plugin is missing an OS support table', - () async { - createFakePlugin('a_plugin', packagesDir.childDirectory('a_plugin')); - - Error? commandError; - final List output = await runCapturingPrint( - runner, ['readme-check'], errorHandler: (Error e) { - commandError = e; - }); + 'fails when app-facing part of a federated plugin is missing an OS support table', + () async { + createFakePlugin('a_plugin', packagesDir.childDirectory('a_plugin')); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('No OS support table found'), - ]), - ); - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['readme-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); + + expect(commandError, isA()); + expect( + output, + containsAllInOrder([contains('No OS support table found')]), + ); + }, + ); test('fails the OS support table is missing the header', () async { - final RepositoryPackage plugin = - createFakePlugin('a_plugin', packagesDir); + final RepositoryPackage plugin = createFakePlugin( + 'a_plugin', + packagesDir, + ); plugin.readmeFile.writeAsStringSync(''' A very useful plugin. @@ -437,9 +498,12 @@ A very useful plugin. Error? commandError; final List output = await runCapturingPrint( - runner, ['readme-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['readme-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -471,17 +535,22 @@ A very useful plugin. Error? commandError; final List output = await runCapturingPrint( - runner, ['readme-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['readme-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ - contains(' OS support table does not match supported platforms:\n' - ' Actual: android, ios, web\n' - ' Documented: android, ios'), + contains( + ' OS support table does not match supported platforms:\n' + ' Actual: android, ios, web\n' + ' Documented: android, ios', + ), contains('Incorrect OS support table'), ]), ); @@ -507,24 +576,28 @@ A very useful plugin. Error? commandError; final List output = await runCapturingPrint( - runner, ['readme-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['readme-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ - contains(' OS support table does not match supported platforms:\n' - ' Actual: android, ios\n' - ' Documented: android, ios, web'), + contains( + ' OS support table does not match supported platforms:\n' + ' Actual: android, ios\n' + ' Documented: android, ios, web', + ), contains('Incorrect OS support table'), ]), ); }); - test('fails if the OS support table has unexpected OS formatting', - () async { + test('fails if the OS support table has unexpected OS formatting', () async { final RepositoryPackage plugin = createFakePlugin( 'a_plugin', packagesDir, @@ -546,16 +619,21 @@ A very useful plugin. Error? commandError; final List output = await runCapturingPrint( - runner, ['readme-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['readme-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ - contains(' Incorrect OS capitalization: android, ios, MacOS, web\n' - ' Please use standard capitalizations: Android, iOS, macOS, Web\n'), + contains( + ' Incorrect OS capitalization: android, ios, MacOS, web\n' + ' Please use standard capitalizations: Android, iOS, macOS, Web\n', + ), contains('Incorrect OS support formatting'), ]), ); @@ -564,8 +642,10 @@ A very useful plugin. group('code blocks', () { test('fails on missing info string', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); package.readmeFile.writeAsStringSync(''' Example: @@ -579,9 +659,12 @@ void main() { Error? commandError; final List output = await runCapturingPrint( - runner, ['readme-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['readme-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -594,8 +677,10 @@ void main() { }); test('allows unknown info strings', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); package.readmeFile.writeAsStringSync(''' Example: @@ -619,8 +704,10 @@ A B C }); test('allows space around info strings', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); package.readmeFile.writeAsStringSync(''' Example: @@ -658,8 +745,10 @@ A B C ``` '''); - final List output = await runCapturingPrint( - runner, ['readme-check', '--require-excerpts']); + final List output = await runCapturingPrint(runner, [ + 'readme-check', + '--require-excerpts', + ]); expect( output, @@ -671,8 +760,10 @@ A B C }); test('fails on missing excerpt tag when requested', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); package.readmeFile.writeAsStringSync(''' Example: @@ -684,10 +775,12 @@ A B C Error? commandError; final List output = await runCapturingPrint( - runner, ['readme-check', '--require-excerpts'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['readme-check', '--require-excerpts'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -696,7 +789,8 @@ A B C contains('Dart code block at line 3 is not managed by code-excerpt.'), // Ensure that the failure message links to instructions. contains( - 'https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md'), + 'https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md', + ), contains('Missing code-excerpt management for code block'), ]), ); diff --git a/script/tool/test/remove_dev_dependencies_command_test.dart b/script/tool/test/remove_dev_dependencies_command_test.dart index 9e2f58b6c9ac..29477893dd3e 100644 --- a/script/tool/test/remove_dev_dependencies_command_test.dart +++ b/script/tool/test/remove_dev_dependencies_command_test.dart @@ -19,12 +19,11 @@ void main() { (:packagesDir, processRunner: _, gitProcessRunner: _, :gitDir) = configureBaseCommandMocks(); - final RemoveDevDependenciesCommand command = RemoveDevDependenciesCommand( - packagesDir, - gitDir: gitDir, + final command = RemoveDevDependenciesCommand(packagesDir, gitDir: gitDir); + runner = CommandRunner( + 'trim_dev_dependencies_command', + 'Test for trim_dev_dependencies_command', ); - runner = CommandRunner('trim_dev_dependencies_command', - 'Test for trim_dev_dependencies_command'); runner.addCommand(command); }); @@ -39,20 +38,22 @@ $addition test('skips if nothing is removed', () async { createFakePackage('a_package', packagesDir, version: '1.0.0'); - final List output = - await runCapturingPrint(runner, ['remove-dev-dependencies']); + final List output = await runCapturingPrint(runner, [ + 'remove-dev-dependencies', + ]); expect( output, - containsAllInOrder([ - contains('SKIPPING: Nothing to remove.'), - ]), + containsAllInOrder([contains('SKIPPING: Nothing to remove.')]), ); }); test('removes dev_dependencies', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '1.0.0'); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '1.0.0', + ); addToPubspec(package, ''' dev_dependencies: @@ -60,24 +61,30 @@ dev_dependencies: another_dependency: ^1.0.0 '''); - final List output = - await runCapturingPrint(runner, ['remove-dev-dependencies']); + final List output = await runCapturingPrint(runner, [ + 'remove-dev-dependencies', + ]); expect( output, - containsAllInOrder([ - contains('Removed dev_dependencies'), - ]), + containsAllInOrder([contains('Removed dev_dependencies')]), + ); + expect( + package.pubspecFile.readAsStringSync(), + isNot(contains('some_dependency:')), + ); + expect( + package.pubspecFile.readAsStringSync(), + isNot(contains('another_dependency:')), ); - expect(package.pubspecFile.readAsStringSync(), - isNot(contains('some_dependency:'))); - expect(package.pubspecFile.readAsStringSync(), - isNot(contains('another_dependency:'))); }); test('removes from examples', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '1.0.0'); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '1.0.0', + ); final RepositoryPackage example = package.getExamples().first; addToPubspec(example, ''' @@ -86,18 +93,21 @@ dev_dependencies: another_dependency: ^1.0.0 '''); - final List output = - await runCapturingPrint(runner, ['remove-dev-dependencies']); + final List output = await runCapturingPrint(runner, [ + 'remove-dev-dependencies', + ]); expect( output, - containsAllInOrder([ - contains('Removed dev_dependencies'), - ]), + containsAllInOrder([contains('Removed dev_dependencies')]), + ); + expect( + package.pubspecFile.readAsStringSync(), + isNot(contains('some_dependency:')), + ); + expect( + package.pubspecFile.readAsStringSync(), + isNot(contains('another_dependency:')), ); - expect(package.pubspecFile.readAsStringSync(), - isNot(contains('some_dependency:'))); - expect(package.pubspecFile.readAsStringSync(), - isNot(contains('another_dependency:'))); }); } diff --git a/script/tool/test/repo_package_info_check_command_test.dart b/script/tool/test/repo_package_info_check_command_test.dart index 01d3195bb626..c7993b5e5974 100644 --- a/script/tool/test/repo_package_info_check_command_test.dart +++ b/script/tool/test/repo_package_info_check_command_test.dart @@ -22,12 +22,11 @@ void main() { configureBaseCommandMocks(); root = packagesDir.fileSystem.currentDirectory; - final RepoPackageInfoCheckCommand command = RepoPackageInfoCheckCommand( - packagesDir, - gitDir: gitDir, - ); + final command = RepoPackageInfoCheckCommand(packagesDir, gitDir: gitDir); runner = CommandRunner( - 'dependabot_test', 'Test for $RepoPackageInfoCheckCommand'); + 'dependabot_test', + 'Test for $RepoPackageInfoCheckCommand', + ); runner.addCommand(command); }); @@ -40,10 +39,14 @@ void main() { void writeCodeOwners(List ownedPackages) { final List subpaths = ownedPackages - .map((RepositoryPackage p) => p.isFederated - ? [p.directory.parent.basename, p.directory.basename] - .join('/') - : p.directory.basename) + .map( + (RepositoryPackage p) => p.isFederated + ? [ + p.directory.parent.basename, + p.directory.basename, + ].join('/') + : p.directory.basename, + ) .toList(); root.childFile('CODEOWNERS').writeAsStringSync(''' ${subpaths.map((String subpath) => 'packages/$subpath/** @someone').join('\n')} @@ -61,22 +64,27 @@ ${subpaths.map((String subpath) => 'packages/$subpath/** @someone').join('\n')} } void writeAutoLabelerYaml(List packages) { - final File labelerYaml = - root.childDirectory('.github').childFile('labeler.yml'); + final File labelerYaml = root + .childDirectory('.github') + .childFile('labeler.yml'); labelerYaml.createSync(recursive: true); - labelerYaml.writeAsStringSync(packages.map((RepositoryPackage p) { - final bool isThirdParty = p.path.contains('third_party/'); - return ''' + labelerYaml.writeAsStringSync( + packages + .map((RepositoryPackage p) { + final bool isThirdParty = p.path.contains('third_party/'); + return ''' -p: ${p.directory.basename} - changed-files: - any-glob-to-any-file: - ${isThirdParty ? 'third_party/' : ''}packages/${p.directory.basename}/**/* '''; - }).join('\n\n')); + }) + .join('\n\n'), + ); } test('passes for correct coverage', () async { - final List packages = [ + final packages = [ createFakePackage('a_package', packagesDir), ]; @@ -87,40 +95,48 @@ ${readmeTableEntry('a_package')} writeAutoLabelerYaml(packages); writeCodeOwners(packages); - final List output = - await runCapturingPrint(runner, ['repo-package-info-check']); + final List output = await runCapturingPrint(runner, [ + 'repo-package-info-check', + ]); - expect(output, - containsAllInOrder([contains('Ran for 1 package(s)')])); + expect( + output, + containsAllInOrder([contains('Ran for 1 package(s)')]), + ); }); - test('passes for federated plugins with only app-facing package listed', - () async { - const String pluginName = 'foo'; - final Directory pluginDir = packagesDir.childDirectory(pluginName); - final List packages = [ - createFakePlugin(pluginName, pluginDir), - createFakePlugin('${pluginName}_platform_interface', pluginDir), - createFakePlugin('${pluginName}_android', pluginDir), - createFakePlugin('${pluginName}_ios', pluginDir), - ]; + test( + 'passes for federated plugins with only app-facing package listed', + () async { + const pluginName = 'foo'; + final Directory pluginDir = packagesDir.childDirectory(pluginName); + final packages = [ + createFakePlugin(pluginName, pluginDir), + createFakePlugin('${pluginName}_platform_interface', pluginDir), + createFakePlugin('${pluginName}_android', pluginDir), + createFakePlugin('${pluginName}_ios', pluginDir), + ]; - root.childFile('README.md').writeAsStringSync(''' + root.childFile('README.md').writeAsStringSync(''' ${readmeTableHeader()} ${readmeTableEntry(pluginName)} '''); - writeAutoLabelerYaml([packages.first]); - writeCodeOwners(packages); + writeAutoLabelerYaml([packages.first]); + writeCodeOwners(packages); - final List output = - await runCapturingPrint(runner, ['repo-package-info-check']); + final List output = await runCapturingPrint(runner, [ + 'repo-package-info-check', + ]); - expect(output, - containsAllInOrder([contains('Ran for 4 package(s)')])); - }); + expect( + output, + containsAllInOrder([contains('Ran for 4 package(s)')]), + ); + }, + ); test('fails for unexpected README table entry', () async { - final List packages = [ + final packages = [ createFakePackage('a_package', packagesDir), ]; @@ -133,20 +149,24 @@ ${readmeTableEntry('another_package')} Error? commandError; final List output = await runCapturingPrint( - runner, ['repo-package-info-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['repo-package-info-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Unknown package "another_package" in root README.md table'), - ])); + output, + containsAllInOrder([ + contains('Unknown package "another_package" in root README.md table'), + ]), + ); }); test('fails for missing README table entry', () async { - final List packages = [ + final packages = [ createFakePackage('a_package', packagesDir), createFakePackage('another_package', packagesDir), ]; @@ -160,28 +180,35 @@ ${readmeTableEntry('another_package')} Error? commandError; final List output = await runCapturingPrint( - runner, ['repo-package-info-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['repo-package-info-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Missing repo root README.md table entry'), - contains('a_package:\n' - ' Missing repo root README.md table entry') - ])); + output, + containsAllInOrder([ + contains('Missing repo root README.md table entry'), + contains( + 'a_package:\n' + ' Missing repo root README.md table entry', + ), + ]), + ); }); test('fails for unexpected format in README table entry', () async { - const String packageName = 'a_package'; + const packageName = 'a_package'; final String encodedTag = Uri.encodeComponent('p: $packageName'); - final List packages = [ + final packages = [ createFakePackage('a_package', packagesDir), ]; - final String entry = '| [$packageName](./packages/$packageName/) | ' + final entry = + '| [$packageName](./packages/$packageName/) | ' 'Some random text | ' '[![pub points](https://img.shields.io/pub/points/$packageName)](https://pub.dev/packages/$packageName/score) | ' '[![popularity](https://img.shields.io/pub/popularity/$packageName)](https://pub.dev/packages/$packageName/score) | ' @@ -197,30 +224,35 @@ $entry Error? commandError; final List output = await runCapturingPrint( - runner, ['repo-package-info-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['repo-package-info-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains( - 'Invalid repo root README.md table entry: "Some random text"'), - contains('a_package:\n' - ' Invalid root README.md table entry') - ])); + output, + containsAllInOrder([ + contains('Invalid repo root README.md table entry: "Some random text"'), + contains( + 'a_package:\n' + ' Invalid root README.md table entry', + ), + ]), + ); }); test('fails for incorrect source link in README table entry', () async { - const String packageName = 'a_package'; + const packageName = 'a_package'; final String encodedTag = Uri.encodeComponent('p: $packageName'); - const String incorrectPackageName = 'a_pakage'; - final List packages = [ + const incorrectPackageName = 'a_pakage'; + final packages = [ createFakePackage('a_package', packagesDir), ]; - final String entry = + final entry = '| [$packageName](./packages/$incorrectPackageName/) | ' '[![pub package](https://img.shields.io/pub/v/$packageName.svg)](https://pub.dev/packages/$packageName) | ' '[![pub points](https://img.shields.io/pub/points/$packageName)](https://pub.dev/packages/$packageName/score) | ' @@ -237,30 +269,38 @@ $entry Error? commandError; final List output = await runCapturingPrint( - runner, ['repo-package-info-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['repo-package-info-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains( - 'Incorrect link in root README.md table: "./packages/$incorrectPackageName/"'), - contains('a_package:\n' - ' Incorrect link in root README.md table') - ])); + output, + containsAllInOrder([ + contains( + 'Incorrect link in root README.md table: "./packages/$incorrectPackageName/"', + ), + contains( + 'a_package:\n' + ' Incorrect link in root README.md table', + ), + ]), + ); }); test('fails for incorrect packages/* link in README table entry', () async { - const String packageName = 'a_package'; + const packageName = 'a_package'; final String encodedTag = Uri.encodeComponent('p: $packageName'); - const String incorrectPackageName = 'a_pakage'; - final List packages = [ + const incorrectPackageName = 'a_pakage'; + final packages = [ createFakePackage('a_package', packagesDir), ]; - final String entry = '| [$packageName](./packages/$packageName/) | ' + final entry = + '| [$packageName](./packages/$packageName/) | ' '[![pub package](https://img.shields.io/pub/v/$packageName.svg)](https://pub.dev/packages/$packageName) | ' '[![pub points](https://img.shields.io/pub/points/$packageName)](https://pub.dev/packages/$incorrectPackageName/score) | ' '[![popularity](https://img.shields.io/pub/popularity/$packageName)](https://pub.dev/packages/$packageName/score) | ' @@ -276,30 +316,38 @@ $entry Error? commandError; final List output = await runCapturingPrint( - runner, ['repo-package-info-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['repo-package-info-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains( - 'Incorrect link in root README.md table: "https://pub.dev/packages/$incorrectPackageName/score"'), - contains('a_package:\n' - ' Incorrect link in root README.md table') - ])); + output, + containsAllInOrder([ + contains( + 'Incorrect link in root README.md table: "https://pub.dev/packages/$incorrectPackageName/score"', + ), + contains( + 'a_package:\n' + ' Incorrect link in root README.md table', + ), + ]), + ); }); test('fails for incorrect labels/* link in README table entry', () async { - const String packageName = 'a_package'; + const packageName = 'a_package'; final String encodedTag = Uri.encodeComponent('p: $packageName'); final String incorrectTag = Uri.encodeComponent('p: a_pakage'); - final List packages = [ + final packages = [ createFakePackage('a_package', packagesDir), ]; - final String entry = '| [$packageName](./packages/$packageName/) | ' + final entry = + '| [$packageName](./packages/$packageName/) | ' '[![pub package](https://img.shields.io/pub/v/$packageName.svg)](https://pub.dev/packages/$packageName) | ' '[![pub points](https://img.shields.io/pub/points/$packageName)](https://pub.dev/packages/$packageName/score) | ' '[![popularity](https://img.shields.io/pub/popularity/$packageName)](https://pub.dev/packages/$packageName/score) | ' @@ -315,30 +363,38 @@ $entry Error? commandError; final List output = await runCapturingPrint( - runner, ['repo-package-info-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['repo-package-info-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains( - 'Incorrect link in root README.md table: "https://github.com/flutter/flutter/labels/$incorrectTag"'), - contains('a_package:\n' - ' Incorrect link in root README.md table') - ])); + output, + containsAllInOrder([ + contains( + 'Incorrect link in root README.md table: "https://github.com/flutter/flutter/labels/$incorrectTag"', + ), + contains( + 'a_package:\n' + ' Incorrect link in root README.md table', + ), + ]), + ); }); test('fails for incorrect packages/* anchor in README table entry', () async { - const String packageName = 'a_package'; + const packageName = 'a_package'; final String encodedTag = Uri.encodeComponent('p: $packageName'); - const String incorrectPackageName = 'a_pakage'; - final List packages = [ + const incorrectPackageName = 'a_pakage'; + final packages = [ createFakePackage('a_package', packagesDir), ]; - final String entry = '| [$packageName](./packages/$packageName/) | ' + final entry = + '| [$packageName](./packages/$packageName/) | ' '[![pub package](https://img.shields.io/pub/v/$packageName.svg)](https://pub.dev/packages/$packageName) | ' '[![pub points](https://img.shields.io/pub/points/$incorrectPackageName)](https://pub.dev/packages/$packageName/score) | ' '[![popularity](https://img.shields.io/pub/popularity/$packageName)](https://pub.dev/packages/$packageName/score) | ' @@ -354,30 +410,38 @@ $entry Error? commandError; final List output = await runCapturingPrint( - runner, ['repo-package-info-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['repo-package-info-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains( - 'Incorrect anchor in root README.md table: "![pub points](https://img.shields.io/pub/points/$incorrectPackageName)"'), - contains('a_package:\n' - ' Incorrect anchor in root README.md table') - ])); + output, + containsAllInOrder([ + contains( + 'Incorrect anchor in root README.md table: "![pub points](https://img.shields.io/pub/points/$incorrectPackageName)"', + ), + contains( + 'a_package:\n' + ' Incorrect anchor in root README.md table', + ), + ]), + ); }); test('fails for incorrect tag query anchor in README table entry', () async { - const String packageName = 'a_package'; + const packageName = 'a_package'; final String encodedTag = Uri.encodeComponent('p: $packageName'); final String incorrectTag = Uri.encodeComponent('p: a_pakage'); - final List packages = [ + final packages = [ createFakePackage('a_package', packagesDir), ]; - final String entry = '| [$packageName](./packages/$packageName/) | ' + final entry = + '| [$packageName](./packages/$packageName/) | ' '[![pub package](https://img.shields.io/pub/v/$packageName.svg)](https://pub.dev/packages/$packageName) | ' '[![pub points](https://img.shields.io/pub/points/$packageName)](https://pub.dev/packages/$packageName/score) | ' '[![popularity](https://img.shields.io/pub/popularity/$packageName)](https://pub.dev/packages/$packageName/score) | ' @@ -393,24 +457,31 @@ $entry Error? commandError; final List output = await runCapturingPrint( - runner, ['repo-package-info-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['repo-package-info-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains( - 'Incorrect anchor in root README.md table: "![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/$incorrectTag?label=)'), - contains('a_package:\n' - ' Incorrect anchor in root README.md table') - ])); + output, + containsAllInOrder([ + contains( + 'Incorrect anchor in root README.md table: "![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/$incorrectTag?label=)', + ), + contains( + 'a_package:\n' + ' Incorrect anchor in root README.md table', + ), + ]), + ); }); test('fails for missing CODEOWNER', () async { - const String packageName = 'a_package'; - final List packages = [ + const packageName = 'a_package'; + final packages = [ createFakePackage('a_package', packagesDir), ]; @@ -423,23 +494,29 @@ ${readmeTableEntry(packageName)} Error? commandError; final List output = await runCapturingPrint( - runner, ['repo-package-info-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['repo-package-info-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Missing CODEOWNERS entry.'), - contains('a_package:\n' - ' Missing CODEOWNERS entry') - ])); + output, + containsAllInOrder([ + contains('Missing CODEOWNERS entry.'), + contains( + 'a_package:\n' + ' Missing CODEOWNERS entry', + ), + ]), + ); }); test('fails for missing auto-labeler entry', () async { - const String packageName = 'a_package'; - final List packages = [ + const packageName = 'a_package'; + final packages = [ createFakePackage('a_package', packagesDir), ]; @@ -452,24 +529,32 @@ ${readmeTableEntry(packageName)} Error? commandError; final List output = await runCapturingPrint( - runner, ['repo-package-info-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['repo-package-info-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Missing a rule in .github/labeler.yml.'), - contains('a_package:\n' - ' Missing auto-labeler entry') - ])); + output, + containsAllInOrder([ + contains('Missing a rule in .github/labeler.yml.'), + contains( + 'a_package:\n' + ' Missing auto-labeler entry', + ), + ]), + ); }); group('ci_config check', () { test('control test', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); root.childFile('README.md').writeAsStringSync(''' ${readmeTableHeader()} @@ -483,8 +568,9 @@ release: batch: false '''); - final List output = - await runCapturingPrint(runner, ['repo-package-info-check']); + final List output = await runCapturingPrint(runner, [ + 'repo-package-info-check', + ]); expect( output, @@ -496,8 +582,10 @@ release: }); test('missing ci_config file is ok', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); root.childFile('README.md').writeAsStringSync(''' ${readmeTableHeader()} @@ -506,20 +594,21 @@ ${readmeTableEntry('a_package')} writeAutoLabelerYaml([package]); writeCodeOwners([package]); - final List output = - await runCapturingPrint(runner, ['repo-package-info-check']); + final List output = await runCapturingPrint(runner, [ + 'repo-package-info-check', + ]); expect( output, - containsAllInOrder([ - contains('No issues found!'), - ]), + containsAllInOrder([contains('No issues found!')]), ); }); test('fails for unknown key', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); root.childFile('README.md').writeAsStringSync(''' ${readmeTableHeader()} @@ -533,9 +622,12 @@ something: true Error? commandError; final List output = await runCapturingPrint( - runner, ['repo-package-info-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['repo-package-info-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -546,10 +638,11 @@ something: true ); }); - test('fails for invalid value type for batch property in release', - () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + test('fails for invalid value type for batch property in release', () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); root.childFile('README.md').writeAsStringSync(''' ${readmeTableHeader()} @@ -564,16 +657,20 @@ release: Error? commandError; final List output = await runCapturingPrint( - runner, ['repo-package-info-check'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['repo-package-info-check'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - 'Invalid value `1` for key `release.batch`, the possible values are [true, false]'), + 'Invalid value `1` for key `release.batch`, the possible values are [true, false]', + ), ]), ); }); diff --git a/script/tool/test/update_dependency_command_test.dart b/script/tool/test/update_dependency_command_test.dart index 738e57d0c579..8464cdd4e0f5 100644 --- a/script/tool/test/update_dependency_command_test.dart +++ b/script/tool/test/update_dependency_command_test.dart @@ -27,22 +27,28 @@ void main() { final GitDir gitDir; (:packagesDir, :processRunner, gitProcessRunner: _, :gitDir) = configureBaseCommandMocks(); - final UpdateDependencyCommand command = UpdateDependencyCommand( + final command = UpdateDependencyCommand( packagesDir, processRunner: processRunner, gitDir: gitDir, - httpClient: - MockClient((http.Request request) => mockHttpResponse!(request)), + httpClient: MockClient( + (http.Request request) => mockHttpResponse!(request), + ), ); runner = CommandRunner( - 'update_dependency_command', 'Test for update-dependency command.'); + 'update_dependency_command', + 'Test for update-dependency command.', + ); runner.addCommand(command); }); /// Adds a dummy 'dependencies:' entries for [dependency] to [package]. - void addDependency(RepositoryPackage package, String dependency, - {String version = '^1.0.0'}) { + void addDependency( + RepositoryPackage package, + String dependency, { + String version = '^1.0.0', + }) { final List lines = package.pubspecFile.readAsLinesSync(); final int dependenciesStartIndex = lines.indexOf('dependencies:'); assert(dependenciesStartIndex != -1); @@ -52,8 +58,11 @@ void main() { /// Adds a 'dev_dependencies:' section with an entry for [dependency] to /// [package]. - void addDevDependency(RepositoryPackage package, String dependency, - {String version = '^1.0.0'}) { + void addDevDependency( + RepositoryPackage package, + String dependency, { + String version = '^1.0.0', + }) { final String originalContent = package.pubspecFile.readAsStringSync(); package.pubspecFile.writeAsStringSync(''' $originalContent @@ -66,9 +75,12 @@ dev_dependencies: test('throws if no target is provided', () async { Error? commandError; final List output = await runCapturingPrint( - runner, ['update-dependency'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['update-dependency'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -81,15 +93,19 @@ dev_dependencies: test('throws if multiple dependencies specified', () async { Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'update-dependency', - '--pub-package', - 'target_package', - '--android-dependency', - 'gradle' - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + [ + 'update-dependency', + '--pub-package', + 'target_package', + '--android-dependency', + 'gradle', + ], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -107,13 +123,13 @@ dev_dependencies: }; Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'update-dependency', - '--pub-package', - 'target_package' - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['update-dependency', '--pub-package', 'target_package'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -132,7 +148,7 @@ dev_dependencies: '--pub-package', 'target_package', '--version', - '1.5.0' + '1.5.0', ]); expect( @@ -144,8 +160,11 @@ dev_dependencies: }); test('skips if the dependency is already the target version', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, examples: []); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + examples: [], + ); addDependency(package, 'target_package', version: '^1.5.0'); final List output = await runCapturingPrint(runner, [ @@ -153,7 +172,7 @@ dev_dependencies: '--pub-package', 'target_package', '--version', - '1.5.0' + '1.5.0', ]); expect( @@ -165,8 +184,11 @@ dev_dependencies: }); test('logs updates', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, examples: []); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + examples: [], + ); addDependency(package, 'target_package'); final List output = await runCapturingPrint(runner, [ @@ -174,20 +196,21 @@ dev_dependencies: '--pub-package', 'target_package', '--version', - '1.5.0' + '1.5.0', ]); expect( output, - containsAllInOrder([ - contains('Updating to "^1.5.0"'), - ]), + containsAllInOrder([contains('Updating to "^1.5.0"')]), ); }); test('updates normal dependency', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, examples: []); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + examples: [], + ); addDependency(package, 'target_package'); await runCapturingPrint(runner, [ @@ -195,18 +218,22 @@ dev_dependencies: '--pub-package', 'target_package', '--version', - '1.5.0' + '1.5.0', ]); - final Dependency? dep = - package.parsePubspec().dependencies['target_package']; + final Dependency? dep = package + .parsePubspec() + .dependencies['target_package']; expect(dep, isA()); expect((dep! as HostedDependency).version.toString(), '^1.5.0'); }); test('updates dev dependency', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, examples: []); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + examples: [], + ); addDevDependency(package, 'target_package'); await runCapturingPrint(runner, [ @@ -214,18 +241,21 @@ dev_dependencies: '--pub-package', 'target_package', '--version', - '1.5.0' + '1.5.0', ]); - final Dependency? dep = - package.parsePubspec().devDependencies['target_package']; + final Dependency? dep = package + .parsePubspec() + .devDependencies['target_package']; expect(dep, isA()); expect((dep! as HostedDependency).version.toString(), '^1.5.0'); }); test('updates dependency in example', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); final RepositoryPackage example = package.getExamples().first; addDevDependency(example, 'target_package'); @@ -234,38 +264,46 @@ dev_dependencies: '--pub-package', 'target_package', '--version', - '1.5.0' + '1.5.0', ]); - final Dependency? dep = - example.parsePubspec().devDependencies['target_package']; + final Dependency? dep = example + .parsePubspec() + .devDependencies['target_package']; expect(dep, isA()); expect((dep! as HostedDependency).version.toString(), '^1.5.0'); }); test('uses provided constraint as-is', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, examples: []); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + examples: [], + ); addDependency(package, 'target_package'); - const String providedConstraint = '>=1.6.0 <3.0.0'; + const providedConstraint = '>=1.6.0 <3.0.0'; await runCapturingPrint(runner, [ 'update-dependency', '--pub-package', 'target_package', '--version', - providedConstraint + providedConstraint, ]); - final Dependency? dep = - package.parsePubspec().dependencies['target_package']; + final Dependency? dep = package + .parsePubspec() + .dependencies['target_package']; expect(dep, isA()); expect((dep! as HostedDependency).version.toString(), providedConstraint); }); test('uses provided version as lower bound for unpinned', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, examples: []); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + examples: [], + ); addDependency(package, 'target_package'); await runCapturingPrint(runner, [ @@ -273,18 +311,22 @@ dev_dependencies: '--pub-package', 'target_package', '--version', - '1.5.0' + '1.5.0', ]); - final Dependency? dep = - package.parsePubspec().dependencies['target_package']; + final Dependency? dep = package + .parsePubspec() + .dependencies['target_package']; expect(dep, isA()); expect((dep! as HostedDependency).version.toString(), '^1.5.0'); }); test('uses provided version as exact version for pinned', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, examples: []); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + examples: [], + ); addDependency(package, 'target_package', version: '1.0.0'); await runCapturingPrint(runner, [ @@ -292,27 +334,27 @@ dev_dependencies: '--pub-package', 'target_package', '--version', - '1.5.0' + '1.5.0', ]); - final Dependency? dep = - package.parsePubspec().dependencies['target_package']; + final Dependency? dep = package + .parsePubspec() + .dependencies['target_package']; expect(dep, isA()); expect((dep! as HostedDependency).version.toString(), '1.5.0'); }); test('uses latest pub version as lower bound for unpinned', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, examples: []); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + examples: [], + ); addDependency(package, 'target_package'); - const Map targetPackagePubResponse = { + const targetPackagePubResponse = { 'name': 'a', - 'versions': [ - '0.0.1', - '1.0.0', - '1.5.0', - ], + 'versions': ['0.0.1', '1.0.0', '1.5.0'], }; mockHttpResponse = (http.Request request) async { if (request.url.pathSegments.last == 'target_package.json') { @@ -327,24 +369,24 @@ dev_dependencies: 'target_package', ]); - final Dependency? dep = - package.parsePubspec().dependencies['target_package']; + final Dependency? dep = package + .parsePubspec() + .dependencies['target_package']; expect(dep, isA()); expect((dep! as HostedDependency).version.toString(), '^1.5.0'); }); test('uses latest pub version as exact version for pinned', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, examples: []); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + examples: [], + ); addDependency(package, 'target_package', version: '1.0.0'); - const Map targetPackagePubResponse = { + const targetPackagePubResponse = { 'name': 'a', - 'versions': [ - '0.0.1', - '1.0.0', - '1.5.0', - ], + 'versions': ['0.0.1', '1.0.0', '1.5.0'], }; mockHttpResponse = (http.Request request) async { if (request.url.pathSegments.last == 'target_package.json') { @@ -359,18 +401,19 @@ dev_dependencies: 'target_package', ]); - final Dependency? dep = - package.parsePubspec().dependencies['target_package']; + final Dependency? dep = package + .parsePubspec() + .dependencies['target_package']; expect(dep, isA()); expect((dep! as HostedDependency).version.toString(), '1.5.0'); }); test('regenerates all pigeon files when updating pigeon', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, extraFiles: [ - 'pigeons/foo.dart', - 'pigeons/bar.dart', - ]); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + extraFiles: ['pigeons/foo.dart', 'pigeons/bar.dart'], + ); addDependency(package, 'pigeon', version: '1.0.0'); await runCapturingPrint(runner, [ @@ -384,67 +427,75 @@ dev_dependencies: expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - 'dart', - const ['pub', 'get'], - package.path, - ), - ProcessCall( - 'dart', - const ['run', 'pigeon', '--input', 'pigeons/foo.dart'], - package.path, - ), - ProcessCall( - 'dart', - const ['run', 'pigeon', '--input', 'pigeons/bar.dart'], - package.path, - ), + ProcessCall('dart', const ['pub', 'get'], package.path), + ProcessCall('dart', const [ + 'run', + 'pigeon', + '--input', + 'pigeons/foo.dart', + ], package.path), + ProcessCall('dart', const [ + 'run', + 'pigeon', + '--input', + 'pigeons/bar.dart', + ], package.path), ]), ); }); - test('warns when regenerating pigeon if there are no pigeon files', - () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); - addDependency(package, 'pigeon', version: '1.0.0'); + test( + 'warns when regenerating pigeon if there are no pigeon files', + () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); + addDependency(package, 'pigeon', version: '1.0.0'); - final List output = await runCapturingPrint(runner, [ - 'update-dependency', - '--pub-package', - 'pigeon', - '--version', - '1.5.0', - ]); + final List output = await runCapturingPrint(runner, [ + 'update-dependency', + '--pub-package', + 'pigeon', + '--version', + '1.5.0', + ]); - expect( - output, - containsAllInOrder([ - contains('No pigeon input files found'), - ]), - ); - }); + expect( + output, + containsAllInOrder([ + contains('No pigeon input files found'), + ]), + ); + }, + ); test('updating pigeon fails if pub get fails', () async { final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - extraFiles: ['pigeons/foo.dart']); + 'a_package', + packagesDir, + extraFiles: ['pigeons/foo.dart'], + ); addDependency(package, 'pigeon', version: '1.0.0'); processRunner.mockProcessesForExecutable['dart'] = [ - FakeProcessInfo(MockProcess(exitCode: 1), ['pub', 'get']) + FakeProcessInfo(MockProcess(exitCode: 1), ['pub', 'get']), ]; Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'update-dependency', - '--pub-package', - 'pigeon', - '--version', - '1.5.0', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + [ + 'update-dependency', + '--pub-package', + 'pigeon', + '--version', + '1.5.0', + ], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -458,8 +509,10 @@ dev_dependencies: test('updating pigeon fails if running pigeon fails', () async { final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - extraFiles: ['pigeons/foo.dart']); + 'a_package', + packagesDir, + extraFiles: ['pigeons/foo.dart'], + ); addDependency(package, 'pigeon', version: '1.0.0'); processRunner.mockProcessesForExecutable['dart'] = [ @@ -468,15 +521,19 @@ dev_dependencies: ]; Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'update-dependency', - '--pub-package', - 'pigeon', - '--version', - '1.5.0', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + [ + 'update-dependency', + '--pub-package', + 'pigeon', + '--version', + '1.5.0', + ], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -489,8 +546,10 @@ dev_dependencies: }); test('regenerates mocks when updating mockito if necessary', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); addDependency(package, 'mockito', version: '1.0.0'); addDevDependency(package, 'build_runner'); @@ -505,62 +564,64 @@ dev_dependencies: expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall( - 'dart', - const ['pub', 'get'], - package.path, - ), - ProcessCall( - 'dart', - const [ - 'run', - 'build_runner', - 'build', - '--delete-conflicting-outputs' - ], - package.path, - ), + ProcessCall('dart', const ['pub', 'get'], package.path), + ProcessCall('dart', const [ + 'run', + 'build_runner', + 'build', + '--delete-conflicting-outputs', + ], package.path), ]), ); }); - test('skips regenerating mocks when there is no build_runner dependency', - () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); - addDependency(package, 'mockito', version: '1.0.0'); + test( + 'skips regenerating mocks when there is no build_runner dependency', + () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); + addDependency(package, 'mockito', version: '1.0.0'); - await runCapturingPrint(runner, [ - 'update-dependency', - '--pub-package', - 'mockito', - '--version', - '1.5.0', - ]); + await runCapturingPrint(runner, [ + 'update-dependency', + '--pub-package', + 'mockito', + '--version', + '1.5.0', + ]); - expect(processRunner.recordedCalls.isEmpty, true); - }); + expect(processRunner.recordedCalls.isEmpty, true); + }, + ); test('updating mockito fails if pub get fails', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); addDependency(package, 'mockito', version: '1.0.0'); addDevDependency(package, 'build_runner'); processRunner.mockProcessesForExecutable['dart'] = [ - FakeProcessInfo(MockProcess(exitCode: 1), ['pub', 'get']) + FakeProcessInfo(MockProcess(exitCode: 1), ['pub', 'get']), ]; Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'update-dependency', - '--pub-package', - 'mockito', - '--version', - '1.5.0', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + [ + 'update-dependency', + '--pub-package', + 'mockito', + '--version', + '1.5.0', + ], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -573,27 +634,35 @@ dev_dependencies: }); test('updating mockito fails if running build_runner fails', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); addDependency(package, 'mockito', version: '1.0.0'); addDevDependency(package, 'build_runner'); processRunner.mockProcessesForExecutable['dart'] = [ FakeProcessInfo(MockProcess(), ['pub', 'get']), - FakeProcessInfo( - MockProcess(exitCode: 1), ['run', 'build_runner']), + FakeProcessInfo(MockProcess(exitCode: 1), [ + 'run', + 'build_runner', + ]), ]; Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'update-dependency', - '--pub-package', - 'mockito', - '--version', - '1.5.0', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + [ + 'update-dependency', + '--pub-package', + 'mockito', + '--version', + '1.5.0', + ], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -607,53 +676,61 @@ dev_dependencies: }); group('Android dependencies', () { - final List invalidGradleAgpVersionsFormat = [ + final invalidGradleAgpVersionsFormat = [ '81', '811.1', '8.123', - '8.12.12' + '8.12.12', ]; - const String invalidGradleAgpVersionError = ''' + const invalidGradleAgpVersionError = ''' A version with a valid format (maximum 2-3 numbers separated by 1-2 periods) must be provided. 1. The first number must have one or two digits 2. The second number must have one or two digits 3. If present, the third number must have a single digit'''; - const String invalidKgpVersionError = ''' + const invalidKgpVersionError = ''' A version with a valid format (3 numbers separated by 2 periods) must be provided. 1. The first number must have one digit 2. The second number must have one digit 3. The third number must have one or two digits'''; group('gradle', () { - for (final String gradleVersion in invalidGradleAgpVersionsFormat) { - test('throws because gradleVersion: $gradleVersion is invalid', - () async { - Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'update-dependency', - '--android-dependency', - 'gradle', - '--version', - gradleVersion, - ], errorHandler: (Error e) { - commandError = e; - }); - - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains(invalidGradleAgpVersionError), - ]), - ); - }); + for (final gradleVersion in invalidGradleAgpVersionsFormat) { + test( + 'throws because gradleVersion: $gradleVersion is invalid', + () async { + Error? commandError; + final List output = await runCapturingPrint( + runner, + [ + 'update-dependency', + '--android-dependency', + 'gradle', + '--version', + gradleVersion, + ], + errorHandler: (Error e) { + commandError = e; + }, + ); + + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains(invalidGradleAgpVersionError), + ]), + ); + }, + ); } test('skips if example app does not run on Android', () async { - final RepositoryPackage package = - createFakePlugin('fake_plugin', packagesDir); + final RepositoryPackage package = createFakePlugin( + 'fake_plugin', + packagesDir, + ); final List output = await runCapturingPrint(runner, [ 'update-dependency', @@ -674,65 +751,78 @@ A version with a valid format (3 numbers separated by 2 periods) must be provide }); test( - 'throws if wrapper does not have distribution URL with expected format', - () async { - final RepositoryPackage package = createFakePlugin( - 'fake_plugin', packagesDir, extraFiles: [ - 'example/android/app/gradle/wrapper/gradle-wrapper.properties' - ]); + 'throws if wrapper does not have distribution URL with expected format', + () async { + final RepositoryPackage package = createFakePlugin( + 'fake_plugin', + packagesDir, + extraFiles: [ + 'example/android/app/gradle/wrapper/gradle-wrapper.properties', + ], + ); - final File gradleWrapperPropertiesFile = package.directory - .childDirectory('example') - .childDirectory('android') - .childDirectory('app') - .childDirectory('gradle') - .childDirectory('wrapper') - .childFile('gradle-wrapper.properties'); + final File gradleWrapperPropertiesFile = package.directory + .childDirectory('example') + .childDirectory('android') + .childDirectory('app') + .childDirectory('gradle') + .childDirectory('wrapper') + .childFile('gradle-wrapper.properties'); - gradleWrapperPropertiesFile.writeAsStringSync(''' + gradleWrapperPropertiesFile.writeAsStringSync(''' How is it even possible that I didn't specify a Gradle distribution? '''); - Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'update-dependency', - '--packages', - package.displayName, - '--android-dependency', - 'gradle', - '--version', - '8.8.8', - ], errorHandler: (Error e) { - commandError = e; - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + [ + 'update-dependency', + '--packages', + package.displayName, + '--android-dependency', + 'gradle', + '--version', + '8.8.8', + ], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains( - 'Unable to find a gradle version entry to update for ${package.displayName}/example.'), - ]), - ); - }); + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains( + 'Unable to find a gradle version entry to update for ${package.displayName}/example.', + ), + ]), + ); + }, + ); - test('succeeds if example app has android/app/gradle directory structure', - () async { - final RepositoryPackage package = createFakePlugin( - 'fake_plugin', packagesDir, extraFiles: [ - 'example/android/app/gradle/wrapper/gradle-wrapper.properties' - ]); - const String newGradleVersion = '8.8.8'; + test( + 'succeeds if example app has android/app/gradle directory structure', + () async { + final RepositoryPackage package = createFakePlugin( + 'fake_plugin', + packagesDir, + extraFiles: [ + 'example/android/app/gradle/wrapper/gradle-wrapper.properties', + ], + ); + const newGradleVersion = '8.8.8'; - final File gradleWrapperPropertiesFile = package.directory - .childDirectory('example') - .childDirectory('android') - .childDirectory('app') - .childDirectory('gradle') - .childDirectory('wrapper') - .childFile('gradle-wrapper.properties'); + final File gradleWrapperPropertiesFile = package.directory + .childDirectory('example') + .childDirectory('android') + .childDirectory('app') + .childDirectory('gradle') + .childDirectory('wrapper') + .childFile('gradle-wrapper.properties'); - gradleWrapperPropertiesFile.writeAsStringSync(r''' + gradleWrapperPropertiesFile.writeAsStringSync(r''' distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME @@ -740,41 +830,48 @@ zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip '''); - await runCapturingPrint(runner, [ - 'update-dependency', - '--packages', - package.displayName, - '--android-dependency', - 'gradle', - '--version', - newGradleVersion, - ]); + await runCapturingPrint(runner, [ + 'update-dependency', + '--packages', + package.displayName, + '--android-dependency', + 'gradle', + '--version', + newGradleVersion, + ]); - final String updatedGradleWrapperPropertiesContents = - gradleWrapperPropertiesFile.readAsStringSync(); - expect( + final String updatedGradleWrapperPropertiesContents = + gradleWrapperPropertiesFile.readAsStringSync(); + expect( updatedGradleWrapperPropertiesContents, contains( - r'distributionUrl=https\://services.gradle.org/distributions/' - 'gradle-$newGradleVersion-all.zip')); - }); + r'distributionUrl=https\://services.gradle.org/distributions/' + 'gradle-$newGradleVersion-all.zip', + ), + ); + }, + ); - test('succeeds if example app has android/gradle directory structure', - () async { - final RepositoryPackage package = createFakePlugin( - 'fake_plugin', packagesDir, extraFiles: [ - 'example/android/gradle/wrapper/gradle-wrapper.properties' - ]); - const String newGradleVersion = '9.9'; + test( + 'succeeds if example app has android/gradle directory structure', + () async { + final RepositoryPackage package = createFakePlugin( + 'fake_plugin', + packagesDir, + extraFiles: [ + 'example/android/gradle/wrapper/gradle-wrapper.properties', + ], + ); + const newGradleVersion = '9.9'; - final File gradleWrapperPropertiesFile = package.directory - .childDirectory('example') - .childDirectory('android') - .childDirectory('gradle') - .childDirectory('wrapper') - .childFile('gradle-wrapper.properties'); + final File gradleWrapperPropertiesFile = package.directory + .childDirectory('example') + .childDirectory('android') + .childDirectory('gradle') + .childDirectory('wrapper') + .childFile('gradle-wrapper.properties'); - gradleWrapperPropertiesFile.writeAsStringSync(r''' + gradleWrapperPropertiesFile.writeAsStringSync(r''' distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME @@ -782,51 +879,57 @@ zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip '''); - await runCapturingPrint(runner, [ - 'update-dependency', - '--packages', - package.displayName, - '--android-dependency', - 'gradle', - '--version', - newGradleVersion, - ]); + await runCapturingPrint(runner, [ + 'update-dependency', + '--packages', + package.displayName, + '--android-dependency', + 'gradle', + '--version', + newGradleVersion, + ]); - final String updatedGradleWrapperPropertiesContents = - gradleWrapperPropertiesFile.readAsStringSync(); - expect( + final String updatedGradleWrapperPropertiesContents = + gradleWrapperPropertiesFile.readAsStringSync(); + expect( updatedGradleWrapperPropertiesContents, contains( - r'distributionUrl=https\://services.gradle.org/distributions/' - 'gradle-$newGradleVersion-all.zip')); - }); + r'distributionUrl=https\://services.gradle.org/distributions/' + 'gradle-$newGradleVersion-all.zip', + ), + ); + }, + ); test( - 'succeeds if example app has android/gradle and android/app/gradle directory structure', - () async { - final RepositoryPackage package = - createFakePlugin('fake_plugin', packagesDir, extraFiles: [ - 'example/android/gradle/wrapper/gradle-wrapper.properties', - 'example/android/app/gradle/wrapper/gradle-wrapper.properties' - ]); - const String newGradleVersion = '9.9'; - - final File gradleWrapperPropertiesFile = package.directory - .childDirectory('example') - .childDirectory('android') - .childDirectory('gradle') - .childDirectory('wrapper') - .childFile('gradle-wrapper.properties'); - - final File gradleAppWrapperPropertiesFile = package.directory - .childDirectory('example') - .childDirectory('android') - .childDirectory('app') - .childDirectory('gradle') - .childDirectory('wrapper') - .childFile('gradle-wrapper.properties'); - - gradleWrapperPropertiesFile.writeAsStringSync(r''' + 'succeeds if example app has android/gradle and android/app/gradle directory structure', + () async { + final RepositoryPackage package = createFakePlugin( + 'fake_plugin', + packagesDir, + extraFiles: [ + 'example/android/gradle/wrapper/gradle-wrapper.properties', + 'example/android/app/gradle/wrapper/gradle-wrapper.properties', + ], + ); + const newGradleVersion = '9.9'; + + final File gradleWrapperPropertiesFile = package.directory + .childDirectory('example') + .childDirectory('android') + .childDirectory('gradle') + .childDirectory('wrapper') + .childFile('gradle-wrapper.properties'); + + final File gradleAppWrapperPropertiesFile = package.directory + .childDirectory('example') + .childDirectory('android') + .childDirectory('app') + .childDirectory('gradle') + .childDirectory('wrapper') + .childFile('gradle-wrapper.properties'); + + gradleWrapperPropertiesFile.writeAsStringSync(r''' distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME @@ -834,7 +937,7 @@ zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip '''); - gradleAppWrapperPropertiesFile.writeAsStringSync(r''' + gradleAppWrapperPropertiesFile.writeAsStringSync(r''' distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME @@ -842,53 +945,60 @@ zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip '''); - await runCapturingPrint(runner, [ - 'update-dependency', - '--packages', - package.displayName, - '--android-dependency', - 'gradle', - '--version', - newGradleVersion, - ]); + await runCapturingPrint(runner, [ + 'update-dependency', + '--packages', + package.displayName, + '--android-dependency', + 'gradle', + '--version', + newGradleVersion, + ]); - final String updatedGradleWrapperPropertiesContents = - gradleWrapperPropertiesFile.readAsStringSync(); - final String updatedGradleAppWrapperPropertiesContents = - gradleAppWrapperPropertiesFile.readAsStringSync(); - expect( + final String updatedGradleWrapperPropertiesContents = + gradleWrapperPropertiesFile.readAsStringSync(); + final String updatedGradleAppWrapperPropertiesContents = + gradleAppWrapperPropertiesFile.readAsStringSync(); + expect( updatedGradleWrapperPropertiesContents, contains( - r'distributionUrl=https\://services.gradle.org/distributions/' - 'gradle-$newGradleVersion-all.zip')); - expect( + r'distributionUrl=https\://services.gradle.org/distributions/' + 'gradle-$newGradleVersion-all.zip', + ), + ); + expect( updatedGradleAppWrapperPropertiesContents, contains( - r'distributionUrl=https\://services.gradle.org/distributions/' - 'gradle-$newGradleVersion-all.zip')); - }); + r'distributionUrl=https\://services.gradle.org/distributions/' + 'gradle-$newGradleVersion-all.zip', + ), + ); + }, + ); - test('succeeds if one example app runs on Android and another does not', - () async { - final RepositoryPackage package = createFakePlugin( - 'fake_plugin', packagesDir, examples: [ - 'example_1', - 'example_2' - ], extraFiles: [ - 'example/example_2/android/app/gradle/wrapper/gradle-wrapper.properties' - ]); - const String newGradleVersion = '8.8.8'; - - final File gradleWrapperPropertiesFile = package.directory - .childDirectory('example') - .childDirectory('example_2') - .childDirectory('android') - .childDirectory('app') - .childDirectory('gradle') - .childDirectory('wrapper') - .childFile('gradle-wrapper.properties'); - - gradleWrapperPropertiesFile.writeAsStringSync(r''' + test( + 'succeeds if one example app runs on Android and another does not', + () async { + final RepositoryPackage package = createFakePlugin( + 'fake_plugin', + packagesDir, + examples: ['example_1', 'example_2'], + extraFiles: [ + 'example/example_2/android/app/gradle/wrapper/gradle-wrapper.properties', + ], + ); + const newGradleVersion = '8.8.8'; + + final File gradleWrapperPropertiesFile = package.directory + .childDirectory('example') + .childDirectory('example_2') + .childDirectory('android') + .childDirectory('app') + .childDirectory('gradle') + .childDirectory('wrapper') + .childFile('gradle-wrapper.properties'); + + gradleWrapperPropertiesFile.writeAsStringSync(r''' distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME @@ -896,38 +1006,45 @@ zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip '''); - await runCapturingPrint(runner, [ - 'update-dependency', - '--packages', - package.displayName, - '--android-dependency', - 'gradle', - '--version', - newGradleVersion, - ]); + await runCapturingPrint(runner, [ + 'update-dependency', + '--packages', + package.displayName, + '--android-dependency', + 'gradle', + '--version', + newGradleVersion, + ]); - final String updatedGradleWrapperPropertiesContents = - gradleWrapperPropertiesFile.readAsStringSync(); - expect( + final String updatedGradleWrapperPropertiesContents = + gradleWrapperPropertiesFile.readAsStringSync(); + expect( updatedGradleWrapperPropertiesContents, contains( - r'distributionUrl=https\://services.gradle.org/distributions/' - 'gradle-$newGradleVersion-all.zip')); - }); + r'distributionUrl=https\://services.gradle.org/distributions/' + 'gradle-$newGradleVersion-all.zip', + ), + ); + }, + ); }); group('agp', () { - for (final String agpVersion in invalidGradleAgpVersionsFormat) { + for (final agpVersion in invalidGradleAgpVersionsFormat) { test('throws because agpVersion: $agpVersion is invalid', () async { Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'update-dependency', - '--android-dependency', - 'androidGradlePlugin', - '--version', - agpVersion, - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + [ + 'update-dependency', + '--android-dependency', + 'androidGradlePlugin', + '--version', + agpVersion, + ], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -940,8 +1057,10 @@ distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip } test('skips if example app does not run on Android', () async { - final RepositoryPackage package = - createFakePlugin('fake_plugin', packagesDir); + final RepositoryPackage package = createFakePlugin( + 'fake_plugin', + packagesDir, + ); final List output = await runCapturingPrint(runner, [ 'update-dependency', @@ -961,19 +1080,22 @@ distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip ); }); - test('succeeds if example app has android/settings.gradle structure', - () async { - final RepositoryPackage package = createFakePlugin( - 'fake_plugin', packagesDir, - extraFiles: ['example/android/settings.gradle']); - const String newAgpVersion = '9.9'; + test( + 'succeeds if example app has android/settings.gradle structure', + () async { + final RepositoryPackage package = createFakePlugin( + 'fake_plugin', + packagesDir, + extraFiles: ['example/android/settings.gradle'], + ); + const newAgpVersion = '9.9'; - final File gradleSettingsFile = package.directory - .childDirectory('example') - .childDirectory('android') - .childFile('settings.gradle'); + final File gradleSettingsFile = package.directory + .childDirectory('example') + .childDirectory('android') + .childFile('settings.gradle'); - gradleSettingsFile.writeAsStringSync(r''' + gradleSettingsFile.writeAsStringSync(r''' ... plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" @@ -983,40 +1105,47 @@ plugins { ... '''); - await runCapturingPrint(runner, [ - 'update-dependency', - '--packages', - package.displayName, - '--android-dependency', - 'androidGradlePlugin', - '--version', - newAgpVersion, - ]); + await runCapturingPrint(runner, [ + 'update-dependency', + '--packages', + package.displayName, + '--android-dependency', + 'androidGradlePlugin', + '--version', + newAgpVersion, + ]); - final String updatedGradleSettingsContents = - gradleSettingsFile.readAsStringSync(); + final String updatedGradleSettingsContents = gradleSettingsFile + .readAsStringSync(); - expect( + expect( updatedGradleSettingsContents, - contains(r'id "com.android.application" version ' - '"$newAgpVersion" apply false')); - }); + contains( + r'id "com.android.application" version ' + '"$newAgpVersion" apply false', + ), + ); + }, + ); - test('succeeds if one example app runs on Android and another does not', - () async { - final RepositoryPackage package = createFakePlugin( - 'fake_plugin', packagesDir, + test( + 'succeeds if one example app runs on Android and another does not', + () async { + final RepositoryPackage package = createFakePlugin( + 'fake_plugin', + packagesDir, examples: ['example_1', 'example_2'], - extraFiles: ['example/example_2/android/settings.gradle']); - const String newAgpVersion = '9.9'; + extraFiles: ['example/example_2/android/settings.gradle'], + ); + const newAgpVersion = '9.9'; - final File gradleSettingsFile = package.directory - .childDirectory('example') - .childDirectory('example_2') - .childDirectory('android') - .childFile('settings.gradle'); + final File gradleSettingsFile = package.directory + .childDirectory('example') + .childDirectory('example_2') + .childDirectory('android') + .childFile('settings.gradle'); - gradleSettingsFile.writeAsStringSync(r''' + gradleSettingsFile.writeAsStringSync(r''' ... plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" @@ -1026,27 +1155,31 @@ plugins { ... '''); - await runCapturingPrint(runner, [ - 'update-dependency', - '--packages', - package.displayName, - '--android-dependency', - 'androidGradlePlugin', - '--version', - newAgpVersion, - ]); + await runCapturingPrint(runner, [ + 'update-dependency', + '--packages', + package.displayName, + '--android-dependency', + 'androidGradlePlugin', + '--version', + newAgpVersion, + ]); - final String updatedGradleSettingsContents = - gradleSettingsFile.readAsStringSync(); + final String updatedGradleSettingsContents = gradleSettingsFile + .readAsStringSync(); - expect( + expect( updatedGradleSettingsContents, - contains(r'id "com.android.application" version ' - '"$newAgpVersion" apply false')); - }); + contains( + r'id "com.android.application" version ' + '"$newAgpVersion" apply false', + ), + ); + }, + ); }); group('kgp', () { - final List invalidKgpVersionsFormat = [ + final invalidKgpVersionsFormat = [ '81', '81.1', '8.123', @@ -1054,44 +1187,52 @@ plugins { '8.12.1', ]; - for (final String kgpVersion in invalidKgpVersionsFormat) { + for (final kgpVersion in invalidKgpVersionsFormat) { test('throws because kgpVersion: $kgpVersion is invalid', () async { Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'update-dependency', - '--android-dependency', - 'kotlinGradlePlugin', - '--version', - kgpVersion, - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + [ + 'update-dependency', + '--android-dependency', + 'kotlinGradlePlugin', + '--version', + kgpVersion, + ], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, - containsAllInOrder([ - contains(invalidKgpVersionError), - ]), + containsAllInOrder([contains(invalidKgpVersionError)]), ); }); } test('skips if example app does not run on Android', () async { - final RepositoryPackage package = - createFakePlugin('fake_plugin', packagesDir); + final RepositoryPackage package = createFakePlugin( + 'fake_plugin', + packagesDir, + ); - final List output = await runCapturingPrint(runner, [ - 'update-dependency', - '--packages', - package.displayName, - '--android-dependency', - 'kotlinGradlePlugin', - '--version', - '2.2.20', - ], errorHandler: (Error e) { - print((e as ToolExit).stackTrace); - }); + final List output = await runCapturingPrint( + runner, + [ + 'update-dependency', + '--packages', + package.displayName, + '--android-dependency', + 'kotlinGradlePlugin', + '--version', + '2.2.20', + ], + errorHandler: (Error e) { + print((e as ToolExit).stackTrace); + }, + ); expect( output, @@ -1101,19 +1242,22 @@ plugins { ); }); - test('succeeds if example app has android/settings.gradle structure', - () async { - final RepositoryPackage package = createFakePlugin( - 'fake_plugin', packagesDir, - extraFiles: ['example/android/settings.gradle']); - const String newKgpVersion = '2.2.20'; + test( + 'succeeds if example app has android/settings.gradle structure', + () async { + final RepositoryPackage package = createFakePlugin( + 'fake_plugin', + packagesDir, + extraFiles: ['example/android/settings.gradle'], + ); + const newKgpVersion = '2.2.20'; - final File gradleSettingsFile = package.directory - .childDirectory('example') - .childDirectory('android') - .childFile('settings.gradle'); + final File gradleSettingsFile = package.directory + .childDirectory('example') + .childDirectory('android') + .childFile('settings.gradle'); - gradleSettingsFile.writeAsStringSync(r''' + gradleSettingsFile.writeAsStringSync(r''' ... plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" @@ -1124,40 +1268,47 @@ plugins { ... '''); - await runCapturingPrint(runner, [ - 'update-dependency', - '--packages', - package.displayName, - '--android-dependency', - 'kotlinGradlePlugin', - '--version', - newKgpVersion, - ]); + await runCapturingPrint(runner, [ + 'update-dependency', + '--packages', + package.displayName, + '--android-dependency', + 'kotlinGradlePlugin', + '--version', + newKgpVersion, + ]); - final String updatedGradleSettingsContents = - gradleSettingsFile.readAsStringSync(); + final String updatedGradleSettingsContents = gradleSettingsFile + .readAsStringSync(); - expect( + expect( updatedGradleSettingsContents, - contains(r' id "org.jetbrains.kotlin.android" version ' - '"$newKgpVersion" apply false')); - }); + contains( + r' id "org.jetbrains.kotlin.android" version ' + '"$newKgpVersion" apply false', + ), + ); + }, + ); - test('succeeds if one example app runs on Android and another does not', - () async { - final RepositoryPackage package = createFakePlugin( - 'fake_plugin', packagesDir, + test( + 'succeeds if one example app runs on Android and another does not', + () async { + final RepositoryPackage package = createFakePlugin( + 'fake_plugin', + packagesDir, examples: ['example_1', 'example_2'], - extraFiles: ['example/example_2/android/settings.gradle']); - const String newKgpVersion = '2.2.20'; + extraFiles: ['example/example_2/android/settings.gradle'], + ); + const newKgpVersion = '2.2.20'; - final File gradleSettingsFile = package.directory - .childDirectory('example') - .childDirectory('example_2') - .childDirectory('android') - .childFile('settings.gradle'); + final File gradleSettingsFile = package.directory + .childDirectory('example') + .childDirectory('example_2') + .childDirectory('android') + .childFile('settings.gradle'); - gradleSettingsFile.writeAsStringSync(r''' + gradleSettingsFile.writeAsStringSync(r''' ... plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" @@ -1168,36 +1319,41 @@ plugins { ... '''); - await runCapturingPrint(runner, [ - 'update-dependency', - '--packages', - package.displayName, - '--android-dependency', - 'kotlinGradlePlugin', - '--version', - newKgpVersion, - ]); + await runCapturingPrint(runner, [ + 'update-dependency', + '--packages', + package.displayName, + '--android-dependency', + 'kotlinGradlePlugin', + '--version', + newKgpVersion, + ]); - final String updatedGradleSettingsContents = - gradleSettingsFile.readAsStringSync(); + final String updatedGradleSettingsContents = gradleSettingsFile + .readAsStringSync(); - expect( + expect( updatedGradleSettingsContents, - contains(r' id "org.jetbrains.kotlin.android" version ' - '"$newKgpVersion" apply false')); - }); + contains( + r' id "org.jetbrains.kotlin.android" version ' + '"$newKgpVersion" apply false', + ), + ); + }, + ); }); group('compileSdk/compileSdkForExamples', () { // Tests if the compileSdk version is updated for the provided // build.gradle file and new compileSdk version to update to. - Future testCompileSdkVersionUpdated( - {required RepositoryPackage package, - required File buildGradleFile, - required String oldCompileSdkVersion, - required String newCompileSdkVersion, - bool runForExamples = false, - bool checkForDeprecatedCompileSdkVersion = false}) async { + Future testCompileSdkVersionUpdated({ + required RepositoryPackage package, + required File buildGradleFile, + required String oldCompileSdkVersion, + required String newCompileSdkVersion, + bool runForExamples = false, + bool checkForDeprecatedCompileSdkVersion = false, + }) async { buildGradleFile.writeAsStringSync(''' android { // Conditional for compatibility with AGP <4.2. @@ -1217,63 +1373,79 @@ android { newCompileSdkVersion, ]); - final String updatedBuildGradleContents = - buildGradleFile.readAsStringSync(); + final String updatedBuildGradleContents = buildGradleFile + .readAsStringSync(); // compileSdkVersion is now deprecated, so if the tool finds any // instances of compileSdk OR compileSdkVersion, it should change it // to compileSdk. See https://developer.android.com/reference/tools/gradle-api/7.2/com/android/build/api/dsl/CommonExtension#compileSdkVersion(kotlin.Int). - expect(updatedBuildGradleContents, - contains('compileSdk $newCompileSdkVersion')); + expect( + updatedBuildGradleContents, + contains('compileSdk $newCompileSdkVersion'), + ); } test('throws if version format is invalid for compileSdk', () async { Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'update-dependency', - '--android-dependency', - 'compileSdk', - '--version', - '834', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + [ + 'update-dependency', + '--android-dependency', + 'compileSdk', + '--version', + '834', + ], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains( - 'A valid Android SDK version number (1-2 digit numbers) must be provided.'), + 'A valid Android SDK version number (1-2 digit numbers) must be provided.', + ), ]), ); }); - test('throws if version format is invalid for compileSdkForExamples', - () async { - Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'update-dependency', - '--android-dependency', - 'compileSdkForExamples', - '--version', - '438', - ], errorHandler: (Error e) { - commandError = e; - }); + test( + 'throws if version format is invalid for compileSdkForExamples', + () async { + Error? commandError; + final List output = await runCapturingPrint( + runner, + [ + 'update-dependency', + '--android-dependency', + 'compileSdkForExamples', + '--version', + '438', + ], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains( - 'A valid Android SDK version number (1-2 digit numbers) must be provided.'), - ]), - ); - }); + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains( + 'A valid Android SDK version number (1-2 digit numbers) must be provided.', + ), + ]), + ); + }, + ); test('skips if plugin does not run on Android', () async { - final RepositoryPackage package = - createFakePlugin('fake_plugin', packagesDir); + final RepositoryPackage package = createFakePlugin( + 'fake_plugin', + packagesDir, + ); final List output = await runCapturingPrint(runner, [ 'update-dependency', @@ -1289,14 +1461,17 @@ android { output, containsAllInOrder([ contains( - 'SKIPPING: Package ${package.displayName} does not run on Android.'), + 'SKIPPING: Package ${package.displayName} does not run on Android.', + ), ]), ); }); test('skips if plugin example does not run on Android', () async { - final RepositoryPackage package = - createFakePlugin('fake_plugin', packagesDir); + final RepositoryPackage package = createFakePlugin( + 'fake_plugin', + packagesDir, + ); final List output = await runCapturingPrint(runner, [ 'update-dependency', @@ -1317,166 +1492,202 @@ android { }); test( - 'throws if build configuration file does not have compileSdk version with expected format for compileSdk', - () async { - final RepositoryPackage package = createFakePlugin( - 'fake_plugin', packagesDir, - extraFiles: ['android/build.gradle']); + 'throws if build configuration file does not have compileSdk version with expected format for compileSdk', + () async { + final RepositoryPackage package = createFakePlugin( + 'fake_plugin', + packagesDir, + extraFiles: ['android/build.gradle'], + ); - final File buildGradleFile = package.directory - .childDirectory('android') - .childFile('build.gradle'); + final File buildGradleFile = package.directory + .childDirectory('android') + .childFile('build.gradle'); - buildGradleFile.writeAsStringSync(''' + buildGradleFile.writeAsStringSync(''' How is it even possible that I didn't specify a compileSdk version? '''); - Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'update-dependency', - '--packages', - package.displayName, - '--android-dependency', - 'compileSdk', - '--version', - '34', - ], errorHandler: (Error e) { - commandError = e; - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + [ + 'update-dependency', + '--packages', + package.displayName, + '--android-dependency', + 'compileSdk', + '--version', + '34', + ], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains( - 'Unable to find a compileSdk version entry to update for ${package.displayName}.'), - ]), - ); - }); + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains( + 'Unable to find a compileSdk version entry to update for ${package.displayName}.', + ), + ]), + ); + }, + ); test( - 'throws if build configuration file does not have compileSdk version with expected format for compileSdkForExamples', - () async { - final RepositoryPackage package = createFakePlugin( - 'fake_plugin', packagesDir, - extraFiles: ['example/android/app/build.gradle']); + 'throws if build configuration file does not have compileSdk version with expected format for compileSdkForExamples', + () async { + final RepositoryPackage package = createFakePlugin( + 'fake_plugin', + packagesDir, + extraFiles: ['example/android/app/build.gradle'], + ); - final File buildGradleFile = package.directory - .childDirectory('example') - .childDirectory('android') - .childDirectory('app') - .childFile('build.gradle'); + final File buildGradleFile = package.directory + .childDirectory('example') + .childDirectory('android') + .childDirectory('app') + .childFile('build.gradle'); - buildGradleFile.writeAsStringSync(''' + buildGradleFile.writeAsStringSync(''' How is it even possible that I didn't specify a compileSdk version? '''); - Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'update-dependency', - '--packages', - package.displayName, - '--android-dependency', - 'compileSdkForExamples', - '--version', - '34', - ], errorHandler: (Error e) { - commandError = e; - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + [ + 'update-dependency', + '--packages', + package.displayName, + '--android-dependency', + 'compileSdkForExamples', + '--version', + '34', + ], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains( - 'Unable to find a compileSdkForExamples version entry to update for ${package.displayName}/example.'), - ]), - ); - }); + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains( + 'Unable to find a compileSdkForExamples version entry to update for ${package.displayName}/example.', + ), + ]), + ); + }, + ); test( - 'succeeds if plugin runs on Android and valid version is supplied for compileSdkVersion entry', - () async { - final RepositoryPackage package = createFakePlugin( - 'fake_plugin', packagesDir, extraFiles: [ - 'android/build.gradle', - 'example/android/app/build.gradle' - ]); - final File buildGradleFile = package.directory - .childDirectory('android') - .childFile('build.gradle'); + 'succeeds if plugin runs on Android and valid version is supplied for compileSdkVersion entry', + () async { + final RepositoryPackage package = createFakePlugin( + 'fake_plugin', + packagesDir, + extraFiles: [ + 'android/build.gradle', + 'example/android/app/build.gradle', + ], + ); + final File buildGradleFile = package.directory + .childDirectory('android') + .childFile('build.gradle'); - await testCompileSdkVersionUpdated( + await testCompileSdkVersionUpdated( package: package, buildGradleFile: buildGradleFile, oldCompileSdkVersion: '8', newCompileSdkVersion: '16', - checkForDeprecatedCompileSdkVersion: true); - }); + checkForDeprecatedCompileSdkVersion: true, + ); + }, + ); test( - 'succeeds if plugin example runs on Android and valid version is supplied for compileSdkVersion entry', - () async { - final RepositoryPackage package = createFakePlugin( - 'fake_plugin', packagesDir, extraFiles: [ - 'android/build.gradle', - 'example/android/app/build.gradle' - ]); - final File exampleBuildGradleFile = package.directory - .childDirectory('example') - .childDirectory('android') - .childDirectory('app') - .childFile('build.gradle'); + 'succeeds if plugin example runs on Android and valid version is supplied for compileSdkVersion entry', + () async { + final RepositoryPackage package = createFakePlugin( + 'fake_plugin', + packagesDir, + extraFiles: [ + 'android/build.gradle', + 'example/android/app/build.gradle', + ], + ); + final File exampleBuildGradleFile = package.directory + .childDirectory('example') + .childDirectory('android') + .childDirectory('app') + .childFile('build.gradle'); - await testCompileSdkVersionUpdated( + await testCompileSdkVersionUpdated( package: package, buildGradleFile: exampleBuildGradleFile, oldCompileSdkVersion: '8', newCompileSdkVersion: '16', runForExamples: true, - checkForDeprecatedCompileSdkVersion: true); - }); + checkForDeprecatedCompileSdkVersion: true, + ); + }, + ); test( - 'succeeds if plugin runs on Android and valid version is supplied for compileSdk entry', - () async { - final RepositoryPackage package = createFakePlugin( - 'fake_plugin', packagesDir, extraFiles: [ - 'android/build.gradle', - 'example/android/app/build.gradle' - ]); + 'succeeds if plugin runs on Android and valid version is supplied for compileSdk entry', + () async { + final RepositoryPackage package = createFakePlugin( + 'fake_plugin', + packagesDir, + extraFiles: [ + 'android/build.gradle', + 'example/android/app/build.gradle', + ], + ); - final File buildGradleFile = package.directory - .childDirectory('android') - .childFile('build.gradle'); - await testCompileSdkVersionUpdated( + final File buildGradleFile = package.directory + .childDirectory('android') + .childFile('build.gradle'); + await testCompileSdkVersionUpdated( package: package, buildGradleFile: buildGradleFile, oldCompileSdkVersion: '8', - newCompileSdkVersion: '16'); - }); + newCompileSdkVersion: '16', + ); + }, + ); test( - 'succeeds if plugin example runs on Android and valid version is supplied for compileSdk entry', - () async { - final RepositoryPackage package = createFakePlugin( - 'fake_plugin', packagesDir, extraFiles: [ - 'android/build.gradle', - 'example/android/app/build.gradle' - ]); + 'succeeds if plugin example runs on Android and valid version is supplied for compileSdk entry', + () async { + final RepositoryPackage package = createFakePlugin( + 'fake_plugin', + packagesDir, + extraFiles: [ + 'android/build.gradle', + 'example/android/app/build.gradle', + ], + ); - final File exampleBuildGradleFile = package.directory - .childDirectory('example') - .childDirectory('android') - .childDirectory('app') - .childFile('build.gradle'); - await testCompileSdkVersionUpdated( + final File exampleBuildGradleFile = package.directory + .childDirectory('example') + .childDirectory('android') + .childDirectory('app') + .childFile('build.gradle'); + await testCompileSdkVersionUpdated( package: package, buildGradleFile: exampleBuildGradleFile, oldCompileSdkVersion: '33', newCompileSdkVersion: '34', - runForExamples: true); - }); + runForExamples: true, + ); + }, + ); }); }); } diff --git a/script/tool/test/update_excerpts_command_test.dart b/script/tool/test/update_excerpts_command_test.dart index c651ec4aac2f..b98e9329392c 100644 --- a/script/tool/test/update_excerpts_command_test.dart +++ b/script/tool/test/update_excerpts_command_test.dart @@ -22,31 +22,33 @@ void runAllTests(MockPlatform platform) { (:packagesDir, :processRunner, gitProcessRunner: _, :gitDir) = configureBaseCommandMocks(platform: platform); runner = CommandRunner('', '') - ..addCommand(UpdateExcerptsCommand( - packagesDir, - platform: platform, - processRunner: processRunner, - gitDir: gitDir, - )); + ..addCommand( + UpdateExcerptsCommand( + packagesDir, + platform: platform, + processRunner: processRunner, + gitDir: gitDir, + ), + ); }); - Future testInjection( - {required String before, - required String source, - required String after, - required String filename, - bool failOnChange = false}) async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + Future testInjection({ + required String before, + required String source, + required String after, + required String filename, + bool failOnChange = false, + }) async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); package.readmeFile.writeAsStringSync(before); package.directory.childFile(filename).writeAsStringSync(source); Object? errorObject; final List output = await runCapturingPrint( runner, - [ - 'update-excerpts', - if (failOnChange) '--fail-on-change', - ], + ['update-excerpts', if (failOnChange) '--fail-on-change'], errorHandler: (Object error) { errorObject = error; }, @@ -58,9 +60,10 @@ void runAllTests(MockPlatform platform) { } test('succeeds when nothing has changed', () async { - const String filename = 'main.dart'; + const filename = 'main.dart'; - const String readme = ''' + const readme = + ''' Example: @@ -68,7 +71,7 @@ Example: A B C ``` '''; - const String source = ''' + const source = ''' FAIL // #docregion SomeSection A B C @@ -76,12 +79,18 @@ A B C FAIL '''; await testInjection( - before: readme, source: source, after: readme, filename: filename); + before: readme, + source: source, + after: readme, + filename: filename, + ); }); test('fails if example injection fails', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); package.readmeFile.writeAsStringSync(''' Example: @@ -100,9 +109,12 @@ FAIL Error? commandError; final List output = await runCapturingPrint( - runner, ['update-excerpts'], errorHandler: (Error e) { - commandError = e; - }); + runner, + ['update-excerpts'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -110,15 +122,17 @@ FAIL containsAllInOrder([ contains('Injecting excerpts failed:'), contains( - 'main.dart: did not find a "// #docregion UnknownSection" pragma'), + 'main.dart: did not find a "// #docregion UnknownSection" pragma', + ), ]), ); }); test('updates files', () async { - const String filename = 'main.dart'; + const filename = 'main.dart'; - const String before = ''' + const before = + ''' Example: @@ -127,7 +141,7 @@ X Y Z ``` '''; - const String source = ''' + const source = ''' FAIL // #docregion SomeSection A B C @@ -135,7 +149,8 @@ A B C FAIL '''; - const String after = ''' + const after = + ''' Example: @@ -145,12 +160,18 @@ A B C '''; await testInjection( - before: before, source: source, after: after, filename: filename); + before: before, + source: source, + after: after, + filename: filename, + ); }); test('fails if READMEs are changed with --fail-on-change', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); package.readmeFile.writeAsStringSync(''' Example: @@ -169,10 +190,12 @@ FAIL Error? commandError; final List output = await runCapturingPrint( - runner, ['update-excerpts', '--fail-on-change'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['update-excerpts', '--fail-on-change'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -181,11 +204,13 @@ FAIL ); }); - test('does not fail if READMEs are not changed with --fail-on-change', - () async { - const String filename = 'main.dart'; + test( + 'does not fail if READMEs are not changed with --fail-on-change', + () async { + const filename = 'main.dart'; - const String readme = ''' + const readme = + ''' Example: @@ -198,7 +223,7 @@ B ``` '''; - const String source = ''' + const source = ''' // #docregion aa A // #enddocregion aa @@ -207,19 +232,21 @@ B // #enddocregion bb '''; - await testInjection( - before: readme, - source: source, - after: readme, - filename: filename, - failOnChange: true, - ); - }); + await testInjection( + before: readme, + source: source, + after: readme, + filename: filename, + failOnChange: true, + ); + }, + ); test('indents the plaster', () async { - const String filename = 'main.dart'; + const filename = 'main.dart'; - const String before = ''' + const before = + ''' Example: @@ -227,7 +254,7 @@ Example: ``` '''; - const String source = ''' + const source = ''' // #docregion SomeSection A // #enddocregion SomeSection @@ -236,7 +263,8 @@ B // #enddocregion SomeSection '''; - const String after = ''' + const after = + ''' Example: @@ -248,13 +276,18 @@ B '''; await testInjection( - before: before, source: source, after: after, filename: filename); + before: before, + source: source, + after: after, + filename: filename, + ); }); test('does not unindent blocks if plaster will not unindent', () async { - const String filename = 'main.dart'; + const filename = 'main.dart'; - const String before = ''' + const before = + ''' Example: @@ -262,7 +295,7 @@ Example: ``` '''; - const String source = ''' + const source = ''' // #docregion SomeSection A // #enddocregion SomeSection @@ -271,7 +304,8 @@ Example: // #enddocregion SomeSection '''; - const String after = ''' + const after = + ''' Example: @@ -283,13 +317,18 @@ Example: '''; await testInjection( - before: before, source: source, after: after, filename: filename); + before: before, + source: source, + after: after, + filename: filename, + ); }); test('unindents blocks', () async { - const String filename = 'main.dart'; + const filename = 'main.dart'; - const String before = ''' + const before = + ''' Example: @@ -297,7 +336,7 @@ Example: ``` '''; - const String source = ''' + const source = ''' // #docregion SomeSection A // #enddocregion SomeSection @@ -306,7 +345,8 @@ Example: // #enddocregion SomeSection '''; - const String after = ''' + const after = + ''' Example: @@ -318,13 +358,18 @@ A '''; await testInjection( - before: before, source: source, after: after, filename: filename); + before: before, + source: source, + after: after, + filename: filename, + ); }); test('unindents blocks and plaster', () async { - const String filename = 'main.dart'; + const filename = 'main.dart'; - const String before = ''' + const before = + ''' Example: @@ -332,7 +377,7 @@ Example: ``` '''; - const String source = ''' + const source = ''' // #docregion SomeSection A // #enddocregion SomeSection @@ -341,7 +386,8 @@ Example: // #enddocregion SomeSection '''; - const String after = ''' + const after = + ''' Example: @@ -353,12 +399,18 @@ A '''; await testInjection( - before: before, source: source, after: after, filename: filename); + before: before, + source: source, + after: after, + filename: filename, + ); }); test('relative path bases', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); package.readmeFile.writeAsStringSync(''' ```dart @@ -454,8 +506,10 @@ Y }); test('logs snippets checked', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + ); package.readmeFile.writeAsStringSync(''' Example: @@ -472,8 +526,9 @@ A B C FAIL '''); - final List output = - await runCapturingPrint(runner, ['update-excerpts']); + final List output = await runCapturingPrint(runner, [ + 'update-excerpts', + ]); expect( output, @@ -484,7 +539,7 @@ FAIL }); group('File type tests', () { - const List> testCases = >[ + const testCases = >[ {'filename': 'main.cc', 'language': 'c++'}, {'filename': 'main.cpp', 'language': 'c++'}, {'filename': 'main.dart'}, @@ -497,17 +552,17 @@ FAIL { 'filename': 'main.css', 'prefix': '/* ', - 'suffix': ' */' + 'suffix': ' */', }, { 'filename': 'main.html', 'prefix': '' + 'suffix': '-->', }, { 'filename': 'main.xml', 'prefix': '' + 'suffix': '-->', }, {'filename': 'main.yaml', 'prefix': '# '}, {'filename': 'main.sh', 'prefix': '# '}, @@ -521,7 +576,8 @@ FAIL final String prefix = testCase['prefix'] ?? '// '; final String suffix = testCase['suffix'] ?? ''; - final String before = ''' + final before = + ''' Example: @@ -530,7 +586,8 @@ X Y Z ``` '''; - final String source = ''' + final source = + ''' FAIL $prefix#docregion SomeSection$suffix A B C @@ -538,7 +595,8 @@ $prefix#enddocregion SomeSection$suffix FAIL '''; - final String after = ''' + final after = + ''' Example: @@ -548,7 +606,11 @@ A B C '''; await testInjection( - before: before, source: source, after: after, filename: filename); + before: before, + source: source, + after: after, + filename: filename, + ); }); } diff --git a/script/tool/test/update_min_sdk_command_test.dart b/script/tool/test/update_min_sdk_command_test.dart index 2de6917a1914..f2b50a12cd6e 100644 --- a/script/tool/test/update_min_sdk_command_test.dart +++ b/script/tool/test/update_min_sdk_command_test.dart @@ -19,30 +19,33 @@ void main() { (:packagesDir, processRunner: _, gitProcessRunner: _, :gitDir) = configureBaseCommandMocks(); - final UpdateMinSdkCommand command = UpdateMinSdkCommand( - packagesDir, - gitDir: gitDir, - ); + final command = UpdateMinSdkCommand(packagesDir, gitDir: gitDir); runner = CommandRunner( - 'update_min_sdk_command', 'Test for update_min_sdk_command'); + 'update_min_sdk_command', + 'Test for update_min_sdk_command', + ); runner.addCommand(command); }); test('fails if --flutter-min is missing', () async { Error? commandError; - await runCapturingPrint(runner, [ - 'update-min-sdk', - ], errorHandler: (Error e) { - commandError = e; - }); + await runCapturingPrint( + runner, + ['update-min-sdk'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); }); test('updates Dart when only Dart is present, with manual range', () async { final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - dartConstraint: '>=3.0.0 <4.0.0'); + 'a_package', + packagesDir, + dartConstraint: '>=3.0.0 <4.0.0', + ); await runCapturingPrint(runner, [ 'update-min-sdk', @@ -50,14 +53,16 @@ void main() { '3.13.0', // Corresponds to Dart 3.1.0 ]); - final String dartVersion = - package.parsePubspec().environment['sdk'].toString(); + final dartVersion = package.parsePubspec().environment['sdk'].toString(); expect(dartVersion, '^3.1.0'); }); test('updates Dart when only Dart is present, with carrot', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, dartConstraint: '^3.0.0'); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + dartConstraint: '^3.0.0', + ); await runCapturingPrint(runner, [ 'update-min-sdk', @@ -65,14 +70,16 @@ void main() { '3.13.0', // Corresponds to Dart 3.1.0 ]); - final String dartVersion = - package.parsePubspec().environment['sdk'].toString(); + final dartVersion = package.parsePubspec().environment['sdk'].toString(); expect(dartVersion, '^3.1.0'); }); test('does not update Dart if it is already higher', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, dartConstraint: '^3.2.0'); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + dartConstraint: '^3.2.0', + ); await runCapturingPrint(runner, [ 'update-min-sdk', @@ -80,17 +87,18 @@ void main() { '3.13.0', // Corresponds to Dart 3.1.0 ]); - final String dartVersion = - package.parsePubspec().environment['sdk'].toString(); + final dartVersion = package.parsePubspec().environment['sdk'].toString(); expect(dartVersion, '^3.2.0'); }); test('updates both Dart and Flutter when both are present', () async { final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - isFlutter: true, - dartConstraint: '>=3.0.0 <4.0.0', - flutterConstraint: '>=3.10.0'); + 'a_package', + packagesDir, + isFlutter: true, + dartConstraint: '>=3.0.0 <4.0.0', + flutterConstraint: '>=3.10.0', + ); await runCapturingPrint(runner, [ 'update-min-sdk', @@ -98,20 +106,23 @@ void main() { '3.13.0', // Corresponds to Dart 3.1.0 ]); - final String dartVersion = - package.parsePubspec().environment['sdk'].toString(); - final String flutterVersion = - package.parsePubspec().environment['flutter'].toString(); + final dartVersion = package.parsePubspec().environment['sdk'].toString(); + final flutterVersion = package + .parsePubspec() + .environment['flutter'] + .toString(); expect(dartVersion, '^3.1.0'); expect(flutterVersion, '>=3.13.0'); }); test('does not update Flutter if it is already higher', () async { final RepositoryPackage package = createFakePackage( - 'a_package', packagesDir, - isFlutter: true, - dartConstraint: '^3.2.0', - flutterConstraint: '>=3.16.0'); + 'a_package', + packagesDir, + isFlutter: true, + dartConstraint: '^3.2.0', + flutterConstraint: '>=3.16.0', + ); await runCapturingPrint(runner, [ 'update-min-sdk', @@ -119,10 +130,11 @@ void main() { '3.13.0', // Corresponds to Dart 3.1.0 ]); - final String dartVersion = - package.parsePubspec().environment['sdk'].toString(); - final String flutterVersion = - package.parsePubspec().environment['flutter'].toString(); + final dartVersion = package.parsePubspec().environment['sdk'].toString(); + final flutterVersion = package + .parsePubspec() + .environment['flutter'] + .toString(); expect(dartVersion, '^3.2.0'); expect(flutterVersion, '>=3.16.0'); }); diff --git a/script/tool/test/update_release_info_command_test.dart b/script/tool/test/update_release_info_command_test.dart index e02280ccafeb..0ad6888008f7 100644 --- a/script/tool/test/update_release_info_command_test.dart +++ b/script/tool/test/update_release_info_command_test.dart @@ -22,38 +22,37 @@ void main() { (:packagesDir, processRunner: _, :gitProcessRunner, :gitDir) = configureBaseCommandMocks(); - final UpdateReleaseInfoCommand command = UpdateReleaseInfoCommand( - packagesDir, - gitDir: gitDir, - ); + final command = UpdateReleaseInfoCommand(packagesDir, gitDir: gitDir); runner = CommandRunner( - 'update_release_info_command', 'Test for update_release_info_command'); + 'update_release_info_command', + 'Test for update_release_info_command', + ); runner.addCommand(command); }); group('flags', () { test('fails if --changelog is missing', () async { Error? commandError; - await runCapturingPrint(runner, [ - 'update-release-info', - '--version=next', - ], errorHandler: (Error e) { - commandError = e; - }); + await runCapturingPrint( + runner, + ['update-release-info', '--version=next'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); }); test('fails if --changelog is blank', () async { Exception? commandError; - await runCapturingPrint(runner, [ - 'update-release-info', - '--version=next', - '--changelog', - '', - ], exceptionHandler: (Exception e) { - commandError = e; - }); + await runCapturingPrint( + runner, + ['update-release-info', '--version=next', '--changelog', ''], + exceptionHandler: (Exception e) { + commandError = e; + }, + ); expect(commandError, isA()); }); @@ -61,24 +60,30 @@ void main() { test('fails if --version is missing', () async { Error? commandError; await runCapturingPrint( - runner, ['update-release-info', '--changelog', 'A change.'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['update-release-info', '--changelog', 'A change.'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); }); test('fails if --version is an unknown value', () async { Exception? commandError; - await runCapturingPrint(runner, [ - 'update-release-info', - '--version=foo', - '--changelog', - 'A change.', - ], exceptionHandler: (Exception e) { - commandError = e; - }); + await runCapturingPrint( + runner, + [ + 'update-release-info', + '--version=foo', + '--changelog', + 'A change.', + ], + exceptionHandler: (Exception e) { + commandError = e; + }, + ); expect(commandError, isA()); }); @@ -86,10 +91,13 @@ void main() { group('changelog', () { test('adds new NEXT section', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '1.0.0'); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '1.0.0', + ); - const String originalChangelog = ''' + const originalChangelog = ''' ## 1.0.0 * Previous changes. @@ -100,11 +108,11 @@ void main() { 'update-release-info', '--version=next', '--changelog', - 'A change.' + 'A change.', ]); final String newChangelog = package.changelogFile.readAsStringSync(); - const String expectedChangeLog = ''' + const expectedChangeLog = ''' ## NEXT * A change. @@ -113,18 +121,19 @@ $originalChangelog'''; expect( output, - containsAllInOrder([ - contains(' Added a NEXT section.'), - ]), + containsAllInOrder([contains(' Added a NEXT section.')]), ); expect(newChangelog, expectedChangeLog); }); test('adds to existing NEXT section', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '1.0.0'); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '1.0.0', + ); - const String originalChangelog = ''' + const originalChangelog = ''' ## NEXT * Already-pending changes. @@ -139,11 +148,11 @@ $originalChangelog'''; 'update-release-info', '--version=next', '--changelog', - 'A change.' + 'A change.', ]); final String newChangelog = package.changelogFile.readAsStringSync(); - const String expectedChangeLog = ''' + const expectedChangeLog = ''' ## NEXT * A change. @@ -154,16 +163,21 @@ $originalChangelog'''; * Old changes. '''; - expect(output, - containsAllInOrder([contains(' Updated NEXT section.')])); + expect( + output, + containsAllInOrder([contains(' Updated NEXT section.')]), + ); expect(newChangelog, expectedChangeLog); }); test('adds new version section', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '1.0.0'); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '1.0.0', + ); - const String originalChangelog = ''' + const originalChangelog = ''' ## 1.0.0 * Previous changes. @@ -174,11 +188,11 @@ $originalChangelog'''; 'update-release-info', '--version=bugfix', '--changelog', - 'A change.' + 'A change.', ]); final String newChangelog = package.changelogFile.readAsStringSync(); - const String expectedChangeLog = ''' + const expectedChangeLog = ''' ## 1.0.1 * A change. @@ -187,18 +201,19 @@ $originalChangelog'''; expect( output, - containsAllInOrder([ - contains(' Added a 1.0.1 section.'), - ]), + containsAllInOrder([contains(' Added a 1.0.1 section.')]), ); expect(newChangelog, expectedChangeLog); }); test('converts existing NEXT section to version section', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '1.0.0'); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '1.0.0', + ); - const String originalChangelog = ''' + const originalChangelog = ''' ## NEXT * Already-pending changes. @@ -213,11 +228,11 @@ $originalChangelog'''; 'update-release-info', '--version=bugfix', '--changelog', - 'A change.' + 'A change.', ]); final String newChangelog = package.changelogFile.readAsStringSync(); - const String expectedChangeLog = ''' + const expectedChangeLog = ''' ## 1.0.1 * A change. @@ -228,16 +243,21 @@ $originalChangelog'''; * Old changes. '''; - expect(output, - containsAllInOrder([contains(' Updated NEXT section.')])); + expect( + output, + containsAllInOrder([contains(' Updated NEXT section.')]), + ); expect(newChangelog, expectedChangeLog); }); test('treats multiple lines as multiple list items', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '1.0.0'); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '1.0.0', + ); - const String originalChangelog = ''' + const originalChangelog = ''' ## 1.0.0 * Previous changes. @@ -248,11 +268,11 @@ $originalChangelog'''; 'update-release-info', '--version=bugfix', '--changelog', - 'First change.\nSecond change.' + 'First change.\nSecond change.', ]); final String newChangelog = package.changelogFile.readAsStringSync(); - const String expectedChangeLog = ''' + const expectedChangeLog = ''' ## 1.0.1 * First change. @@ -263,27 +283,31 @@ $originalChangelog'''; expect(newChangelog, expectedChangeLog); }); - test('adds a period to any lines missing it, and removes whitespace', - () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '1.0.0'); + test( + 'adds a period to any lines missing it, and removes whitespace', + () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '1.0.0', + ); - const String originalChangelog = ''' + const originalChangelog = ''' ## 1.0.0 * Previous changes. '''; - package.changelogFile.writeAsStringSync(originalChangelog); + package.changelogFile.writeAsStringSync(originalChangelog); - await runCapturingPrint(runner, [ - 'update-release-info', - '--version=bugfix', - '--changelog', - 'First change \nSecond change' - ]); + await runCapturingPrint(runner, [ + 'update-release-info', + '--version=bugfix', + '--changelog', + 'First change \nSecond change', + ]); - final String newChangelog = package.changelogFile.readAsStringSync(); - const String expectedChangeLog = ''' + final String newChangelog = package.changelogFile.readAsStringSync(); + const expectedChangeLog = ''' ## 1.0.1 * First change. @@ -291,14 +315,18 @@ $originalChangelog'''; $originalChangelog'''; - expect(newChangelog, expectedChangeLog); - }); + expect(newChangelog, expectedChangeLog); + }, + ); test('handles non-standard changelog format', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '1.0.0'); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '1.0.0', + ); - const String originalChangelog = ''' + const originalChangelog = ''' # 1.0.0 * A version with the wrong heading format. @@ -309,27 +337,32 @@ $originalChangelog'''; 'update-release-info', '--version=next', '--changelog', - 'A change.' + 'A change.', ]); final String newChangelog = package.changelogFile.readAsStringSync(); - const String expectedChangeLog = ''' + const expectedChangeLog = ''' ## NEXT * A change. $originalChangelog'''; - expect(output, - containsAllInOrder([contains(' Added a NEXT section.')])); + expect( + output, + containsAllInOrder([contains(' Added a NEXT section.')]), + ); expect(newChangelog, expectedChangeLog); }); test('adds to existing NEXT section using - list style', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '1.0.0'); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '1.0.0', + ); - const String originalChangelog = ''' + const originalChangelog = ''' ## NEXT - Already-pending changes. @@ -344,11 +377,11 @@ $originalChangelog'''; 'update-release-info', '--version=next', '--changelog', - 'A change.' + 'A change.', ]); final String newChangelog = package.changelogFile.readAsStringSync(); - const String expectedChangeLog = ''' + const expectedChangeLog = ''' ## NEXT - A change. @@ -359,20 +392,29 @@ $originalChangelog'''; - Previous changes. '''; - expect(output, - containsAllInOrder([contains(' Updated NEXT section.')])); + expect( + output, + containsAllInOrder([contains(' Updated NEXT section.')]), + ); expect(newChangelog, expectedChangeLog); }); test('skips for "minimal" when there are no changes at all', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '1.0.1'); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '1.0.1', + ); gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' packages/different_package/lib/foo.dart -''')), - ]; +''', + ), + ), + ]; final String originalChangelog = package.changelogFile.readAsStringSync(); final List output = await runCapturingPrint(runner, [ @@ -386,23 +428,31 @@ packages/different_package/lib/foo.dart expect(version, '1.0.1'); expect(package.changelogFile.readAsStringSync(), originalChangelog); expect( - output, - containsAllInOrder([ - contains('No changes to package'), - contains('Skipped 1 package') - ])); + output, + containsAllInOrder([ + contains('No changes to package'), + contains('Skipped 1 package'), + ]), + ); }); test('skips for "minimal" when there are only test changes', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '1.0.1'); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '1.0.1', + ); gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' packages/a_package/test/a_test.dart packages/a_package/example/integration_test/another_test.dart -''')), - ]; +''', + ), + ), + ]; final String originalChangelog = package.changelogFile.readAsStringSync(); final List output = await runCapturingPrint(runner, [ @@ -416,36 +466,46 @@ packages/a_package/example/integration_test/another_test.dart expect(version, '1.0.1'); expect(package.changelogFile.readAsStringSync(), originalChangelog); expect( - output, - containsAllInOrder([ - contains('No non-exempt changes to package'), - contains('Skipped 1 package') - ])); + output, + containsAllInOrder([ + contains('No non-exempt changes to package'), + contains('Skipped 1 package'), + ]), + ); }); test('fails if CHANGELOG.md is missing', () async { createFakePackage('a_package', packagesDir, includeCommonFiles: false); Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'update-release-info', - '--version=minor', - '--changelog', - 'A change.', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + [ + 'update-release-info', + '--version=minor', + '--changelog', + 'A change.', + ], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); - expect(output, - containsAllInOrder([contains(' Missing CHANGELOG.md.')])); + expect( + output, + containsAllInOrder([contains(' Missing CHANGELOG.md.')]), + ); }); test('fails if CHANGELOG.md has unexpected NEXT block format', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '1.0.0'); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '1.0.0', + ); - const String originalChangelog = ''' + const originalChangelog = ''' ## NEXT Some free-form text that isn't a list. @@ -457,83 +517,108 @@ Some free-form text that isn't a list. package.changelogFile.writeAsStringSync(originalChangelog); Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'update-release-info', - '--version=minor', - '--changelog', - 'A change.', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + [ + 'update-release-info', + '--version=minor', + '--changelog', + 'A change.', + ], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains(' Existing NEXT section has unrecognized format.') - ])); + output, + containsAllInOrder([ + contains(' Existing NEXT section has unrecognized format.'), + ]), + ); }); }); group('pubspec', () { test('does not change for --next', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '1.0.0'); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '1.0.0', + ); await runCapturingPrint(runner, [ 'update-release-info', '--version=next', '--changelog', - 'A change.' + 'A change.', ]); final String version = package.parsePubspec().version?.toString() ?? ''; expect(version, '1.0.0'); }); - test('updates bugfix version for pre-1.0 without existing build number', - () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '0.1.0'); - - final List output = await runCapturingPrint(runner, [ - 'update-release-info', - '--version=bugfix', - '--changelog', - 'A change.', - ]); - - final String version = package.parsePubspec().version?.toString() ?? ''; - expect(version, '0.1.0+1'); - expect( + test( + 'updates bugfix version for pre-1.0 without existing build number', + () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '0.1.0', + ); + + final List output = await runCapturingPrint(runner, [ + 'update-release-info', + '--version=bugfix', + '--changelog', + 'A change.', + ]); + + final String version = package.parsePubspec().version?.toString() ?? ''; + expect(version, '0.1.0+1'); + expect( output, - containsAllInOrder( - [contains(' Incremented version to 0.1.0+1')])); - }); - - test('updates bugfix version for pre-1.0 with existing build number', - () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '0.1.0+2'); - - final List output = await runCapturingPrint(runner, [ - 'update-release-info', - '--version=bugfix', - '--changelog', - 'A change.', - ]); + containsAllInOrder([ + contains(' Incremented version to 0.1.0+1'), + ]), + ); + }, + ); - final String version = package.parsePubspec().version?.toString() ?? ''; - expect(version, '0.1.0+3'); - expect( + test( + 'updates bugfix version for pre-1.0 with existing build number', + () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '0.1.0+2', + ); + + final List output = await runCapturingPrint(runner, [ + 'update-release-info', + '--version=bugfix', + '--changelog', + 'A change.', + ]); + + final String version = package.parsePubspec().version?.toString() ?? ''; + expect(version, '0.1.0+3'); + expect( output, - containsAllInOrder( - [contains(' Incremented version to 0.1.0+3')])); - }); + containsAllInOrder([ + contains(' Incremented version to 0.1.0+3'), + ]), + ); + }, + ); test('updates bugfix version for post-1.0', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '1.0.1'); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '1.0.1', + ); final List output = await runCapturingPrint(runner, [ 'update-release-info', @@ -545,14 +630,19 @@ Some free-form text that isn't a list. final String version = package.parsePubspec().version?.toString() ?? ''; expect(version, '1.0.2'); expect( - output, - containsAllInOrder( - [contains(' Incremented version to 1.0.2')])); + output, + containsAllInOrder([ + contains(' Incremented version to 1.0.2'), + ]), + ); }); test('updates minor version for pre-1.0', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '0.1.0+2'); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '0.1.0+2', + ); final List output = await runCapturingPrint(runner, [ 'update-release-info', @@ -564,14 +654,19 @@ Some free-form text that isn't a list. final String version = package.parsePubspec().version?.toString() ?? ''; expect(version, '0.1.1'); expect( - output, - containsAllInOrder( - [contains(' Incremented version to 0.1.1')])); + output, + containsAllInOrder([ + contains(' Incremented version to 0.1.1'), + ]), + ); }); test('updates minor version for post-1.0', () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '1.0.1'); + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '1.0.1', + ); final List output = await runCapturingPrint(runner, [ 'update-release-info', @@ -583,77 +678,105 @@ Some free-form text that isn't a list. final String version = package.parsePubspec().version?.toString() ?? ''; expect(version, '1.1.0'); expect( - output, - containsAllInOrder( - [contains(' Incremented version to 1.1.0')])); + output, + containsAllInOrder([ + contains(' Incremented version to 1.1.0'), + ]), + ); }); - test('updates bugfix version for "minimal" with publish-worthy changes', - () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '1.0.1'); - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: ''' + test( + 'updates bugfix version for "minimal" with publish-worthy changes', + () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '1.0.1', + ); + gitProcessRunner.mockProcessesForExecutable['git-diff'] = + [ + FakeProcessInfo( + MockProcess( + stdout: ''' packages/a_package/lib/plugin.dart -''')), - ]; - - final List output = await runCapturingPrint(runner, [ - 'update-release-info', - '--version=minimal', - '--changelog', - 'A change.', - ]); - - final String version = package.parsePubspec().version?.toString() ?? ''; - expect(version, '1.0.2'); - expect( +''', + ), + ), + ]; + + final List output = await runCapturingPrint(runner, [ + 'update-release-info', + '--version=minimal', + '--changelog', + 'A change.', + ]); + + final String version = package.parsePubspec().version?.toString() ?? ''; + expect(version, '1.0.2'); + expect( output, - containsAllInOrder( - [contains(' Incremented version to 1.0.2')])); - }); + containsAllInOrder([ + contains(' Incremented version to 1.0.2'), + ]), + ); + }, + ); - test('no version change for "minimal" with non-publish-worthy changes', - () async { - final RepositoryPackage package = - createFakePackage('a_package', packagesDir, version: '1.0.1'); - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: ''' + test( + 'no version change for "minimal" with non-publish-worthy changes', + () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + version: '1.0.1', + ); + gitProcessRunner.mockProcessesForExecutable['git-diff'] = + [ + FakeProcessInfo( + MockProcess( + stdout: ''' packages/a_package/test/plugin_test.dart -''')), - ]; - - await runCapturingPrint(runner, [ - 'update-release-info', - '--version=minimal', - '--changelog', - 'A change.', - ]); - - final String version = package.parsePubspec().version?.toString() ?? ''; - expect(version, '1.0.1'); - }); +''', + ), + ), + ]; + + await runCapturingPrint(runner, [ + 'update-release-info', + '--version=minimal', + '--changelog', + 'A change.', + ]); + + final String version = package.parsePubspec().version?.toString() ?? ''; + expect(version, '1.0.1'); + }, + ); test('fails if there is no version in pubspec', () async { createFakePackage('a_package', packagesDir, version: null); Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'update-release-info', - '--version=minor', - '--changelog', - 'A change.', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + [ + 'update-release-info', + '--version=minor', + '--changelog', + 'A change.', + ], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder( - [contains('Could not determine current version.')])); + output, + containsAllInOrder([ + contains('Could not determine current version.'), + ]), + ); }); }); } diff --git a/script/tool/test/util.dart b/script/tool/test/util.dart index fe0c81fd6dcd..493e4641309f 100644 --- a/script/tool/test/util.dart +++ b/script/tool/test/util.dart @@ -35,8 +35,9 @@ String getFlutterCommand(Platform platform) => /// Creates a packages directory at an arbitrary location in the given /// filesystem. Directory createPackagesDirectory(FileSystem fileSystem) { - final Directory packagesDir = - fileSystem.currentDirectory.childDirectory('packages'); + final Directory packagesDir = fileSystem.currentDirectory.childDirectory( + 'packages', + ); packagesDir.createSync(); return packagesDir; } @@ -143,18 +144,21 @@ RepositoryPackage createFakePackage( String? directoryName, String? publishTo, }) { - final RepositoryPackage package = - RepositoryPackage(parentDirectory.childDirectory(directoryName ?? name)); + final package = RepositoryPackage( + parentDirectory.childDirectory(directoryName ?? name), + ); package.directory.createSync(recursive: true); package.libDirectory.createSync(); - createFakePubspec(package, - name: name, - isFlutter: isFlutter, - version: version, - flutterConstraint: flutterConstraint, - dartConstraint: dartConstraint, - publishTo: publishTo); + createFakePubspec( + package, + name: name, + isFlutter: isFlutter, + version: version, + flutterConstraint: flutterConstraint, + dartConstraint: dartConstraint, + publishTo: publishTo, + ); if (includeCommonFiles) { package.changelogFile.writeAsStringSync(''' ## $version @@ -165,31 +169,39 @@ RepositoryPackage createFakePackage( } if (examples.length == 1) { - createFakePackage('${name}_example', package.directory, - directoryName: examples.first, + createFakePackage( + '${name}_example', + package.directory, + directoryName: examples.first, + examples: [], + includeCommonFiles: false, + isFlutter: isFlutter, + publishTo: 'none', + flutterConstraint: flutterConstraint, + dartConstraint: dartConstraint, + ); + } else if (examples.isNotEmpty) { + final Directory examplesDirectory = getExampleDir(package)..createSync(); + for (final exampleName in examples) { + createFakePackage( + exampleName, + examplesDirectory, examples: [], includeCommonFiles: false, isFlutter: isFlutter, publishTo: 'none', flutterConstraint: flutterConstraint, - dartConstraint: dartConstraint); - } else if (examples.isNotEmpty) { - final Directory examplesDirectory = getExampleDir(package)..createSync(); - for (final String exampleName in examples) { - createFakePackage(exampleName, examplesDirectory, - examples: [], - includeCommonFiles: false, - isFlutter: isFlutter, - publishTo: 'none', - flutterConstraint: flutterConstraint, - dartConstraint: dartConstraint); + dartConstraint: dartConstraint, + ); } } final p.Context posixContext = p.posix; - for (final String file in extraFiles) { - childFileWithSubcomponents(package.directory, posixContext.split(file)) - .createSync(recursive: true); + for (final file in extraFiles) { + childFileWithSubcomponents( + package.directory, + posixContext.split(file), + ).createSync(recursive: true); } return package; @@ -214,18 +226,20 @@ void createFakePubspec( }) { isPlugin |= platformSupport.isNotEmpty; - String environmentSection = ''' + var environmentSection = + ''' environment: sdk: "$dartConstraint" '''; - String dependenciesSection = ''' + var dependenciesSection = ''' dependencies: '''; - String pluginSection = ''; + var pluginSection = ''; // Add Flutter-specific entries if requested. if (isFlutter) { - environmentSection += ''' + environmentSection += + ''' flutter: "$flutterConstraint" '''; dependenciesSection += ''' @@ -241,8 +255,11 @@ flutter: '''; for (final MapEntry platform in platformSupport.entries) { - pluginSection += - _pluginPlatformSection(platform.key, platform.value, name); + pluginSection += _pluginPlatformSection( + platform.key, + platform.value, + name, + ); } } } @@ -250,10 +267,11 @@ flutter: // Default to a fake server to avoid ever accidentally publishing something // from a test. Does not use 'none' since that changes the behavior of some // commands. - final String publishToSection = + final publishToSection = 'publish_to: ${publishTo ?? 'http://no_pub_server.com'}'; - final String yaml = ''' + final yaml = + ''' name: $name ${(version != null) ? 'version: $version' : ''} $publishToSection @@ -270,18 +288,20 @@ $pluginSection } String _pluginPlatformSection( - String platform, PlatformDetails support, String packageName) { - String entry = ''; + String platform, + PlatformDetails support, + String packageName, +) { + var entry = ''; // Build the main plugin entry. if (support.type == PlatformSupport.federated) { - entry = ''' + entry = + ''' $platform: default_package: ${packageName}_$platform '''; } else { - final List lines = [ - ' $platform:', - ]; + final lines = [' $platform:']; switch (platform) { case platformAndroid: lines.add(' package: io.flutter.plugins.fake'); @@ -292,8 +312,9 @@ String _pluginPlatformSection( case platformMacOS: case platformWindows: if (support.hasNativeCode) { - final String className = - platform == platformIOS ? 'FLTFakePlugin' : 'FakePlugin'; + final className = platform == platformIOS + ? 'FLTFakePlugin' + : 'FakePlugin'; lines.add(' pluginClass: $className'); } if (support.hasDartCode) { @@ -322,8 +343,8 @@ Future> runCapturingPrint( void Function(Error error)? errorHandler, void Function(Exception error)? exceptionHandler, }) async { - final List prints = []; - final ZoneSpecification spec = ZoneSpecification( + final prints = []; + final spec = ZoneSpecification( print: (_, __, ___, String message) { prints.add(message); }, @@ -349,8 +370,11 @@ Future> runCapturingPrint( /// Information about a process to return from [RecordingProcessRunner]. class FakeProcessInfo { - const FakeProcessInfo(this.process, - [this.expectedInitialArgs = const [], this.runCallback]); + const FakeProcessInfo( + this.process, [ + this.expectedInitialArgs = const [], + this.runCallback, + ]); /// The process to return. final io.Process process; @@ -395,8 +419,9 @@ class RecordingProcessRunner extends ProcessRunner { }) async { recordedCalls.add(ProcessCall(executable, args, workingDir?.path)); final io.Process? processToReturn = _runFakeProcess(executable, args); - final int exitCode = - processToReturn == null ? 0 : await processToReturn.exitCode; + final int exitCode = processToReturn == null + ? 0 + : await processToReturn.exitCode; if (exitOnError && (exitCode != 0)) { throw io.ProcessException(executable, args); } @@ -418,14 +443,16 @@ class RecordingProcessRunner extends ProcessRunner { recordedCalls.add(ProcessCall(executable, args, workingDir?.path)); final io.Process? process = _runFakeProcess(executable, args); - final List? processStdout = - await process?.stdout.transform(stdoutEncoding.decoder).toList(); + final List? processStdout = await process?.stdout + .transform(stdoutEncoding.decoder) + .toList(); final String stdout = processStdout?.join() ?? ''; - final List? processStderr = - await process?.stderr.transform(stderrEncoding.decoder).toList(); + final List? processStderr = await process?.stderr + .transform(stderrEncoding.decoder) + .toList(); final String stderr = processStderr?.join() ?? ''; - final io.ProcessResult result = process == null + final result = process == null ? io.ProcessResult(1, 0, '', '') : io.ProcessResult(process.pid, await process.exitCode, stdout, stderr); @@ -437,11 +464,15 @@ class RecordingProcessRunner extends ProcessRunner { } @override - Future start(String executable, List args, - {Directory? workingDirectory}) async { + Future start( + String executable, + List args, { + Directory? workingDirectory, + }) async { recordedCalls.add(ProcessCall(executable, args, workingDirectory?.path)); return Future.value( - _runFakeProcess(executable, args) ?? MockProcess()); + _runFakeProcess(executable, args) ?? MockProcess(), + ); } /// Returns the fake process for the given executable and args after running @@ -452,11 +483,15 @@ class RecordingProcessRunner extends ProcessRunner { if (fakes.isNotEmpty) { final FakeProcessInfo fake = fakes.removeAt(0); if (args.length < fake.expectedInitialArgs.length || - !listsEqual(args.sublist(0, fake.expectedInitialArgs.length), - fake.expectedInitialArgs)) { - throw StateError('Next fake process for $executable expects arguments ' - '[${fake.expectedInitialArgs.join(', ')}] but was called with ' - 'arguments [${args.join(', ')}]'); + !listsEqual( + args.sublist(0, fake.expectedInitialArgs.length), + fake.expectedInitialArgs, + )) { + throw StateError( + 'Next fake process for $executable expects arguments ' + '[${fake.expectedInitialArgs.join(', ')}] but was called with ' + 'arguments [${args.join(', ')}]', + ); } fake.runCallback?.call(); return fake.process; @@ -492,7 +527,7 @@ class ProcessCall { @override String toString() { - final List command = [executable, ...args]; + final command = [executable, ...args]; return '"${command.join(' ')}" in $workingDir'; } } @@ -510,15 +545,17 @@ class ProcessCall { RecordingProcessRunner processRunner, RecordingProcessRunner gitProcessRunner, GitDir gitDir, -}) configureBaseCommandMocks({ +}) +configureBaseCommandMocks({ Platform? platform, RecordingProcessRunner? customProcessRunner, RecordingProcessRunner? customGitProcessRunner, }) { final FileSystem fileSystem = MemoryFileSystem( - style: (platform?.isWindows ?? false) - ? FileSystemStyle.windows - : FileSystemStyle.posix); + style: (platform?.isWindows ?? false) + ? FileSystemStyle.windows + : FileSystemStyle.posix, + ); final Directory packagesDir = createPackagesDirectory(fileSystem); final RecordingProcessRunner processRunner = diff --git a/script/tool/test/version_check_command_test.dart b/script/tool/test/version_check_command_test.dart index d23b7535fda0..6f2e6470b6ee 100644 --- a/script/tool/test/version_check_command_test.dart +++ b/script/tool/test/version_check_command_test.dart @@ -23,10 +23,12 @@ void testAllowedVersion( bool allowed = true, NextVersionType? nextVersionType, }) { - final Version main = Version.parse(mainVersion); - final Version head = Version.parse(headVersion); - final Map allowedVersions = - getAllowedNextVersions(main, newVersion: head); + final main = Version.parse(mainVersion); + final head = Version.parse(headVersion); + final Map allowedVersions = getAllowedNextVersions( + main, + newVersion: head, + ); if (allowed) { expect(allowedVersions, contains(head)); if (nextVersionType != null) { @@ -38,7 +40,7 @@ void testAllowedVersion( } void main() { - const String indentation = ' '; + const indentation = ' '; group('VersionCheckCommand', () { late MockPlatform mockPlatform; late Directory packagesDir; @@ -58,19 +60,25 @@ void main() { // Default to simulating the plugin never having been published. mockHttpStatus = 404; mockHttpResponse = null; - final MockClient mockClient = MockClient((http.Request request) async { - return http.Response(json.encode(mockHttpResponse), - mockHttpResponse == null ? mockHttpStatus : 200); + final mockClient = MockClient((http.Request request) async { + return http.Response( + json.encode(mockHttpResponse), + mockHttpResponse == null ? mockHttpStatus : 200, + ); }); - final VersionCheckCommand command = VersionCheckCommand(packagesDir, - processRunner: processRunner, - platform: mockPlatform, - gitDir: gitDir, - httpClient: mockClient); + final command = VersionCheckCommand( + packagesDir, + processRunner: processRunner, + platform: mockPlatform, + gitDir: gitDir, + httpClient: mockClient, + ); runner = CommandRunner( - 'version_check_command', 'Test for $VersionCheckCommand'); + 'version_check_command', + 'Test for $VersionCheckCommand', + ); runner.addCommand(command); }); @@ -78,10 +86,12 @@ void main() { createFakePlugin('plugin', packagesDir, version: '2.0.0'); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; - final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main']); + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; + final List output = await runCapturingPrint(runner, [ + 'version-check', + '--base-sha=main', + ]); expect( output, @@ -91,53 +101,59 @@ void main() { ]), ); expect( - gitProcessRunner.recordedCalls, - containsAllInOrder(const [ - ProcessCall( - 'git-show', ['main:packages/plugin/pubspec.yaml'], null) - ])); + gitProcessRunner.recordedCalls, + containsAllInOrder(const [ + ProcessCall('git-show', [ + 'main:packages/plugin/pubspec.yaml', + ], null), + ]), + ); }); test('denies invalid version', () async { createFakePlugin('plugin', packagesDir, version: '0.2.0'); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 0.0.1')), - ]; + FakeProcessInfo(MockProcess(stdout: 'version: 0.0.1')), + ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['version-check', '--base-sha=main'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Incorrectly updated version.'), - ])); + output, + containsAllInOrder([contains('Incorrectly updated version.')]), + ); expect( - gitProcessRunner.recordedCalls, - containsAllInOrder(const [ - ProcessCall( - 'git-show', ['main:packages/plugin/pubspec.yaml'], null) - ])); + gitProcessRunner.recordedCalls, + containsAllInOrder(const [ + ProcessCall('git-show', [ + 'main:packages/plugin/pubspec.yaml', + ], null), + ]), + ); }); test('uses merge-base without explicit base-sha', () async { createFakePlugin('plugin', packagesDir, version: '2.0.0'); gitProcessRunner.mockProcessesForExecutable['git-merge-base'] = [ - FakeProcessInfo(MockProcess(stdout: 'abc123')), - FakeProcessInfo(MockProcess(stdout: 'abc123')), - ]; + FakeProcessInfo(MockProcess(stdout: 'abc123')), + FakeProcessInfo(MockProcess(stdout: 'abc123')), + ]; gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; - final List output = - await runCapturingPrint(runner, ['version-check']); + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; + final List output = await runCapturingPrint(runner, [ + 'version-check', + ]); expect( output, @@ -147,19 +163,25 @@ void main() { ]), ); expect( - gitProcessRunner.recordedCalls, - containsAllInOrder(const [ - ProcessCall('git-merge-base', - ['--fork-point', 'main', 'HEAD'], null), - ProcessCall('git-show', - ['abc123:packages/plugin/pubspec.yaml'], null), - ])); + gitProcessRunner.recordedCalls, + containsAllInOrder(const [ + ProcessCall('git-merge-base', [ + '--fork-point', + 'main', + 'HEAD', + ], null), + ProcessCall('git-show', [ + 'abc123:packages/plugin/pubspec.yaml', + ], null), + ]), + ); }); test('allows valid version for new package.', () async { createFakePlugin('plugin', packagesDir, version: '1.0.0'); - final List output = - await runCapturingPrint(runner, ['version-check']); + final List output = await runCapturingPrint(runner, [ + 'version-check', + ]); expect( output, @@ -174,63 +196,77 @@ void main() { createFakePlugin('plugin', packagesDir, version: '0.6.1'); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 0.6.2')), - ]; - final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main']); + FakeProcessInfo(MockProcess(stdout: 'version: 0.6.2')), + ]; + final List output = await runCapturingPrint(runner, [ + 'version-check', + '--base-sha=main', + ]); expect( output, containsAllInOrder([ - contains('New version is lower than previous version. ' - 'This is assumed to be a revert.'), + contains( + 'New version is lower than previous version. ' + 'This is assumed to be a revert.', + ), ]), ); expect( - gitProcessRunner.recordedCalls, - containsAllInOrder(const [ - ProcessCall( - 'git-show', ['main:packages/plugin/pubspec.yaml'], null) - ])); + gitProcessRunner.recordedCalls, + containsAllInOrder(const [ + ProcessCall('git-show', [ + 'main:packages/plugin/pubspec.yaml', + ], null), + ]), + ); }); test('denies lower version that could not be a simple revert', () async { createFakePlugin('plugin', packagesDir, version: '0.5.1'); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 0.6.2')), - ]; + FakeProcessInfo(MockProcess(stdout: 'version: 0.6.2')), + ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['version-check', '--base-sha=main'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Incorrectly updated version.'), - ])); + output, + containsAllInOrder([contains('Incorrectly updated version.')]), + ); expect( - gitProcessRunner.recordedCalls, - containsAllInOrder(const [ - ProcessCall( - 'git-show', ['main:packages/plugin/pubspec.yaml'], null) - ])); + gitProcessRunner.recordedCalls, + containsAllInOrder(const [ + ProcessCall('git-show', [ + 'main:packages/plugin/pubspec.yaml', + ], null), + ]), + ); }); test('allows minor changes to platform interfaces', () async { - createFakePlugin('plugin_platform_interface', packagesDir, - version: '1.1.0'); + createFakePlugin( + 'plugin_platform_interface', + packagesDir, + version: '1.1.0', + ); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; - final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main']); + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; + final List output = await runCapturingPrint(runner, [ + 'version-check', + '--base-sha=main', + ]); expect( output, containsAllInOrder([ @@ -239,158 +275,184 @@ void main() { ]), ); expect( - gitProcessRunner.recordedCalls, - containsAllInOrder(const [ - ProcessCall( - 'git-show', - [ - 'main:packages/plugin_platform_interface/pubspec.yaml' - ], - null) - ])); + gitProcessRunner.recordedCalls, + containsAllInOrder(const [ + ProcessCall('git-show', [ + 'main:packages/plugin_platform_interface/pubspec.yaml', + ], null), + ]), + ); }); - test('disallows breaking changes to platform interfaces by default', - () async { - createFakePlugin('plugin_platform_interface', packagesDir, - version: '2.0.0'); - gitProcessRunner.mockProcessesForExecutable['git-show'] = - [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; - Error? commandError; - final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main'], + test( + 'disallows breaking changes to platform interfaces by default', + () async { + createFakePlugin( + 'plugin_platform_interface', + packagesDir, + version: '2.0.0', + ); + gitProcessRunner.mockProcessesForExecutable['git-show'] = + [ + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['version-check', '--base-sha=main'], errorHandler: (Error e) { - commandError = e; - }); + commandError = e; + }, + ); - expect(commandError, isA()); - expect( + expect(commandError, isA()); + expect( output, containsAllInOrder([ contains( - ' Breaking changes to platform interfaces are not allowed ' - 'without explicit justification.\n' - ' See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md ' - 'for more information.'), - ])); - expect( + ' Breaking changes to platform interfaces are not allowed ' + 'without explicit justification.\n' + ' See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md ' + 'for more information.', + ), + ]), + ); + expect( gitProcessRunner.recordedCalls, containsAllInOrder(const [ - ProcessCall( - 'git-show', - [ - 'main:packages/plugin_platform_interface/pubspec.yaml' - ], - null) - ])); - }); + ProcessCall('git-show', [ + 'main:packages/plugin_platform_interface/pubspec.yaml', + ], null), + ]), + ); + }, + ); - test('allows breaking changes to platform interfaces with override label', - () async { - createFakePlugin('plugin_platform_interface', packagesDir, - version: '2.0.0'); - gitProcessRunner.mockProcessesForExecutable['git-show'] = - [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; + test( + 'allows breaking changes to platform interfaces with override label', + () async { + createFakePlugin( + 'plugin_platform_interface', + packagesDir, + version: '2.0.0', + ); + gitProcessRunner.mockProcessesForExecutable['git-show'] = + [ + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; - final List output = await runCapturingPrint(runner, [ - 'version-check', - '--base-sha=main', - '--pr-labels=some label,override: allow breaking change,another-label' - ]); + final List output = await runCapturingPrint(runner, [ + 'version-check', + '--base-sha=main', + '--pr-labels=some label,override: allow breaking change,another-label', + ]); - expect( - output, - containsAllInOrder([ - contains('Allowing breaking change to plugin_platform_interface ' - 'due to the "override: allow breaking change" label.'), - contains('Ran for 1 package(s) (1 with warnings)'), - ]), - ); - expect( + expect( + output, + containsAllInOrder([ + contains( + 'Allowing breaking change to plugin_platform_interface ' + 'due to the "override: allow breaking change" label.', + ), + contains('Ran for 1 package(s) (1 with warnings)'), + ]), + ); + expect( gitProcessRunner.recordedCalls, containsAllInOrder(const [ - ProcessCall( - 'git-show', - [ - 'main:packages/plugin_platform_interface/pubspec.yaml' - ], - null) - ])); - }); + ProcessCall('git-show', [ + 'main:packages/plugin_platform_interface/pubspec.yaml', + ], null), + ]), + ); + }, + ); - test('allows breaking changes to platform interfaces with bypass flag', - () async { - createFakePlugin('plugin_platform_interface', packagesDir, - version: '2.0.0'); - gitProcessRunner.mockProcessesForExecutable['git-show'] = - [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; - final List output = await runCapturingPrint(runner, [ - 'version-check', - '--base-sha=main', - '--ignore-platform-interface-breaks' - ]); + test( + 'allows breaking changes to platform interfaces with bypass flag', + () async { + createFakePlugin( + 'plugin_platform_interface', + packagesDir, + version: '2.0.0', + ); + gitProcessRunner.mockProcessesForExecutable['git-show'] = + [ + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; + final List output = await runCapturingPrint(runner, [ + 'version-check', + '--base-sha=main', + '--ignore-platform-interface-breaks', + ]); - expect( - output, - containsAllInOrder([ - contains('Allowing breaking change to plugin_platform_interface due ' - 'to --ignore-platform-interface-breaks'), - contains('Ran for 1 package(s) (1 with warnings)'), - ]), - ); - expect( + expect( + output, + containsAllInOrder([ + contains( + 'Allowing breaking change to plugin_platform_interface due ' + 'to --ignore-platform-interface-breaks', + ), + contains('Ran for 1 package(s) (1 with warnings)'), + ]), + ); + expect( gitProcessRunner.recordedCalls, containsAllInOrder(const [ - ProcessCall( - 'git-show', - [ - 'main:packages/plugin_platform_interface/pubspec.yaml' - ], - null) - ])); - }); + ProcessCall('git-show', [ + 'main:packages/plugin_platform_interface/pubspec.yaml', + ], null), + ]), + ); + }, + ); - test('Allow empty lines in front of the first version in CHANGELOG', - () async { - const String version = '1.0.1'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: version); - const String changelog = ''' + test( + 'Allow empty lines in front of the first version in CHANGELOG', + () async { + const version = '1.0.1'; + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: version, + ); + const changelog = + ''' ## $version * Some changes. '''; - plugin.changelogFile.writeAsStringSync(changelog); - final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main']); - expect( - output, - containsAllInOrder([ - contains('Running for plugin'), - ]), - ); - }); + plugin.changelogFile.writeAsStringSync(changelog); + final List output = await runCapturingPrint(runner, [ + 'version-check', + '--base-sha=main', + ]); + expect( + output, + containsAllInOrder([contains('Running for plugin')]), + ); + }, + ); test('Throws if versions in changelog and pubspec do not match', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.1'); - const String changelog = ''' + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.1', + ); + const changelog = ''' ## 1.0.2 * Some changes. '''; plugin.changelogFile.writeAsStringSync(changelog); Error? commandError; final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main', '--against-pub'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['version-check', '--base-sha=main', '--against-pub'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -402,90 +464,112 @@ void main() { }); test('Success if CHANGELOG and pubspec versions match', () async { - const String version = '1.0.1'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: version); + const version = '1.0.1'; + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: version, + ); - const String changelog = ''' + const changelog = + ''' ## $version * Some changes. '''; plugin.changelogFile.writeAsStringSync(changelog); - final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main']); + final List output = await runCapturingPrint(runner, [ + 'version-check', + '--base-sha=main', + ]); expect( output, - containsAllInOrder([ - contains('Running for plugin'), - ]), + containsAllInOrder([contains('Running for plugin')]), ); }); test( - 'Fail if pubspec version only matches an older version listed in CHANGELOG', - () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.0'); + 'Fail if pubspec version only matches an older version listed in CHANGELOG', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.0', + ); - const String changelog = ''' + const changelog = ''' ## 1.0.1 * Some changes. ## 1.0.0 * Some other changes. '''; - plugin.changelogFile.writeAsStringSync(changelog); - bool hasError = false; - final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main', '--against-pub'], + plugin.changelogFile.writeAsStringSync(changelog); + var hasError = false; + final List output = await runCapturingPrint( + runner, + ['version-check', '--base-sha=main', '--against-pub'], errorHandler: (Error e) { - expect(e, isA()); - hasError = true; - }); - expect(hasError, isTrue); + expect(e, isA()); + hasError = true; + }, + ); + expect(hasError, isTrue); - expect( - output, - containsAllInOrder([ - contains('Versions in CHANGELOG.md and pubspec.yaml do not match.'), - ]), - ); - }); + expect( + output, + containsAllInOrder([ + contains('Versions in CHANGELOG.md and pubspec.yaml do not match.'), + ]), + ); + }, + ); - test('Allow NEXT as a placeholder for gathering CHANGELOG entries', - () async { - const String version = '1.0.0'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: version); + test( + 'Allow NEXT as a placeholder for gathering CHANGELOG entries', + () async { + const version = '1.0.0'; + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: version, + ); - const String changelog = ''' + const changelog = + ''' ## NEXT * Some changes that won't be published until the next time there's a release. ## $version * Some other changes. '''; - plugin.changelogFile.writeAsStringSync(changelog); - gitProcessRunner.mockProcessesForExecutable['git-show'] = - [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; + plugin.changelogFile.writeAsStringSync(changelog); + gitProcessRunner.mockProcessesForExecutable['git-show'] = + [ + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; - final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main']); - expect( - output, - containsAllInOrder([ - contains('Running for plugin'), - contains('Found NEXT; validating next version in the CHANGELOG.'), - ]), - ); - }); + final List output = await runCapturingPrint(runner, [ + 'version-check', + '--base-sha=main', + ]); + expect( + output, + containsAllInOrder([ + contains('Running for plugin'), + contains('Found NEXT; validating next version in the CHANGELOG.'), + ]), + ); + }, + ); test('Fail if NEXT appears after a version', () async { - const String version = '1.0.1'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: version); + const version = '1.0.1'; + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: version, + ); - const String changelog = ''' + const changelog = + ''' ## $version * Some changes. ## NEXT @@ -494,35 +578,44 @@ void main() { * Some other changes. '''; plugin.changelogFile.writeAsStringSync(changelog); - bool hasError = false; + var hasError = false; final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main', '--against-pub'], - errorHandler: (Error e) { - expect(e, isA()); - hasError = true; - }); + runner, + ['version-check', '--base-sha=main', '--against-pub'], + errorHandler: (Error e) { + expect(e, isA()); + hasError = true; + }, + ); expect(hasError, isTrue); expect( output, containsAllInOrder([ - contains('When bumping the version for release, the NEXT section ' - "should be incorporated into the new version's release notes.") + contains( + 'When bumping the version for release, the NEXT section ' + "should be incorporated into the new version's release notes.", + ), ]), ); }); - test('Fail if NEXT is left in the CHANGELOG when adding a version bump', - () async { - const String version = '1.0.1'; - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: version); - gitProcessRunner.mockProcessesForExecutable['git-show'] = - [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; + test( + 'Fail if NEXT is left in the CHANGELOG when adding a version bump', + () async { + const version = '1.0.1'; + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: version, + ); + gitProcessRunner.mockProcessesForExecutable['git-show'] = + [ + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; - const String changelog = ''' + const changelog = + ''' ## NEXT * Some changes that should have been folded in 1.0.1. ## $version @@ -530,37 +623,47 @@ void main() { ## 1.0.0 * Some other changes. '''; - plugin.changelogFile.writeAsStringSync(changelog); + plugin.changelogFile.writeAsStringSync(changelog); - bool hasError = false; - final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main'], + var hasError = false; + final List output = await runCapturingPrint( + runner, + ['version-check', '--base-sha=main'], errorHandler: (Error e) { - expect(e, isA()); - hasError = true; - }); - expect(hasError, isTrue); + expect(e, isA()); + hasError = true; + }, + ); + expect(hasError, isTrue); - expect( - output, - containsAllInOrder([ - contains('When bumping the version for release, the NEXT section ' - "should be incorporated into the new version's release notes."), - contains('plugin:\n' - ' CHANGELOG.md failed validation.'), - ]), - ); - }); + expect( + output, + containsAllInOrder([ + contains( + 'When bumping the version for release, the NEXT section ' + "should be incorporated into the new version's release notes.", + ), + contains( + 'plugin:\n' + ' CHANGELOG.md failed validation.', + ), + ]), + ); + }, + ); test('fails if the version increases without replacing NEXT', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.1'); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.1', + ); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; - const String changelog = ''' + const changelog = ''' ## NEXT * Some changes that should be listed as part of 1.0.1. ## 1.0.0 @@ -568,29 +671,36 @@ void main() { '''; plugin.changelogFile.writeAsStringSync(changelog); - bool hasError = false; + var hasError = false; final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main'], - errorHandler: (Error e) { - expect(e, isA()); - hasError = true; - }); + runner, + ['version-check', '--base-sha=main'], + errorHandler: (Error e) { + expect(e, isA()); + hasError = true; + }, + ); expect(hasError, isTrue); expect( output, containsAllInOrder([ - contains('When bumping the version for release, the NEXT section ' - "should be incorporated into the new version's release notes.") + contains( + 'When bumping the version for release, the NEXT section ' + "should be incorporated into the new version's release notes.", + ), ]), ); }); test('allows NEXT for a revert', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.0'); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.0', + ); - const String changelog = ''' + const changelog = ''' ## NEXT * Some changes that should be listed as part of 1.0.1. ## 1.0.0 @@ -600,26 +710,33 @@ void main() { plugin.changelogFile.writeAsStringSync(changelog); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.1')), - ]; + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.1')), + ]; - final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main']); + final List output = await runCapturingPrint(runner, [ + 'version-check', + '--base-sha=main', + ]); expect( output, containsAllInOrder([ - contains('New version is lower than previous version. ' - 'This is assumed to be a revert.'), + contains( + 'New version is lower than previous version. ' + 'This is assumed to be a revert.', + ), ]), ); }); // This handles imports of a package with a NEXT section. test('allows NEXT for a new package', () async { - final RepositoryPackage plugin = - createFakePackage('a_package', packagesDir, version: '1.0.0'); + final RepositoryPackage plugin = createFakePackage( + 'a_package', + packagesDir, + version: '1.0.0', + ); - const String changelog = ''' + const changelog = ''' ## NEXT * Some changes that should be listed in the next release. ## 1.0.0 @@ -627,8 +744,10 @@ void main() { '''; plugin.changelogFile.writeAsStringSync(changelog); - final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main']); + final List output = await runCapturingPrint(runner, [ + 'version-check', + '--base-sha=main', + ]); expect( output, containsAllInOrder([ @@ -639,10 +758,13 @@ void main() { }); test('fails gracefully if the first entry uses the wrong style', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.0'); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.0', + ); - const String changelog = ''' + const changelog = ''' # 1.0.0 * Some changes for a later release. ## 0.9.0 @@ -651,88 +773,102 @@ void main() { plugin.changelogFile.writeAsStringSync(changelog); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'version-check', - '--base-sha=main', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['version-check', '--base-sha=main'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains('Unable to find a version in CHANGELOG.md'), - contains('The current version should be on a line starting with ' - '"## ", either on the first non-empty line or after a "## NEXT" ' - 'section.'), + contains( + 'The current version should be on a line starting with ' + '"## ", either on the first non-empty line or after a "## NEXT" ' + 'section.', + ), ]), ); }); test( - 'fails gracefully if the version headers are not found due to using the wrong style', - () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.0'); + 'fails gracefully if the version headers are not found due to using the wrong style', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.0', + ); - const String changelog = ''' + const changelog = ''' ## NEXT * Some changes for a later release. # 1.0.0 * Some other changes. '''; - plugin.changelogFile.writeAsStringSync(changelog); - gitProcessRunner.mockProcessesForExecutable['git-show'] = - [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; + plugin.changelogFile.writeAsStringSync(changelog); + gitProcessRunner.mockProcessesForExecutable['git-show'] = + [ + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; - Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'version-check', - '--base-sha=main', - ], errorHandler: (Error e) { - commandError = e; - }); + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['version-check', '--base-sha=main'], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('Unable to find a version in CHANGELOG.md'), - contains('The current version should be on a line starting with ' + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains('Unable to find a version in CHANGELOG.md'), + contains( + 'The current version should be on a line starting with ' '"## ", either on the first non-empty line or after a "## NEXT" ' - 'section.'), - ]), - ); - }); + 'section.', + ), + ]), + ); + }, + ); test('fails gracefully if the version is unparseable', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.0'); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.0', + ); - const String changelog = ''' + const changelog = ''' ## Alpha * Some changes. '''; plugin.changelogFile.writeAsStringSync(changelog); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; Error? commandError; - final List output = await runCapturingPrint(runner, [ - 'version-check', - '--base-sha=main', - ], errorHandler: (Error e) { - commandError = e; - }); + final List output = await runCapturingPrint( + runner, + ['version-check', '--base-sha=main'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -744,75 +880,82 @@ void main() { }); group('missing change detection', () { - Future> runWithMissingChangeDetection(List extraArgs, - {void Function(Error error)? errorHandler}) async { - return runCapturingPrint( - runner, - [ - 'version-check', - '--base-sha=main', - '--check-for-missing-changes', - ...extraArgs, - ], - errorHandler: errorHandler); + Future> runWithMissingChangeDetection( + List extraArgs, { + void Function(Error error)? errorHandler, + }) async { + return runCapturingPrint(runner, [ + 'version-check', + '--base-sha=main', + '--check-for-missing-changes', + ...extraArgs, + ], errorHandler: errorHandler); } test('passes for unchanged packages', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.0'); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.0', + ); - const String changelog = ''' + const changelog = ''' ## 1.0.0 * Some changes. '''; plugin.changelogFile.writeAsStringSync(changelog); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: '')), - ]; + [FakeProcessInfo(MockProcess(stdout: ''))]; - final List output = - await runWithMissingChangeDetection([]); + final List output = await runWithMissingChangeDetection( + [], + ); expect( output, - containsAllInOrder([ - contains('Running for plugin'), - ]), + containsAllInOrder([contains('Running for plugin')]), ); }); - test( - 'fails if a version and CHANGELOG change is missing from a change ' + test('fails if a version and CHANGELOG change is missing from a change ' 'that does not pass the exemption check', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.0'); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.0', + ); - const String changelog = ''' + const changelog = ''' ## 1.0.0 * Some changes. '''; plugin.changelogFile.writeAsStringSync(changelog); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin/lib/plugin.dart -''')), - ]; +''', + ), + ), + ]; Error? commandError; final List output = await runWithMissingChangeDetection( - [], errorHandler: (Error e) { - commandError = e; - }); + [], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -821,93 +964,112 @@ packages/plugin/lib/plugin.dart contains('No version change found'), contains('No CHANGELOG change found.'), contains('"update-release-info" command'), - contains('plugin:\n' - ' Missing version change'), + contains( + 'plugin:\n' + ' Missing version change', + ), ]), ); }); test('passes version change requirement when version changes', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.1'); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.1', + ); - const String changelog = ''' + const changelog = ''' ## 1.0.1 * Some changes. '''; plugin.changelogFile.writeAsStringSync(changelog); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin/lib/plugin.dart packages/plugin/CHANGELOG.md packages/plugin/pubspec.yaml -''')), - ]; +''', + ), + ), + ]; - final List output = - await runWithMissingChangeDetection([]); + final List output = await runWithMissingChangeDetection( + [], + ); expect( output, - containsAllInOrder([ - contains('Running for plugin'), - ]), + containsAllInOrder([contains('Running for plugin')]), ); }); test('version change check ignores files outside the package', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.0'); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.0', + ); - const String changelog = ''' + const changelog = ''' ## 1.0.0 * Some changes. '''; plugin.changelogFile.writeAsStringSync(changelog); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin_a/lib/plugin.dart tool/plugin/lib/plugin.dart -''')), - ]; +''', + ), + ), + ]; - final List output = - await runWithMissingChangeDetection([]); + final List output = await runWithMissingChangeDetection( + [], + ); expect( output, - containsAllInOrder([ - contains('Running for plugin'), - ]), + containsAllInOrder([contains('Running for plugin')]), ); }); test('allows missing version change for exempt changes', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.0'); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.0', + ); - const String changelog = ''' + const changelog = ''' ## 1.0.0 * Some changes. '''; plugin.changelogFile.writeAsStringSync(changelog); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin/example/android/.pluginToolsConfig.yaml packages/plugin/example/android/lint-baseline.xml packages/plugin/example/android/src/androidTest/foo/bar/FooTest.java @@ -916,192 +1078,239 @@ packages/plugin/example/ios/RunnerUITests/info.plist packages/plugin/darwin/Tests/Foo.swift packages/plugin/analysis_options.yaml packages/plugin/CHANGELOG.md -''')), - ]; +''', + ), + ), + ]; - final List output = - await runWithMissingChangeDetection([]); + final List output = await runWithMissingChangeDetection( + [], + ); expect( output, - containsAllInOrder([ - contains('Running for plugin'), - ]), + containsAllInOrder([contains('Running for plugin')]), ); }); test('allows missing version change with override label', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.0'); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.0', + ); - const String changelog = ''' + const changelog = ''' ## 1.0.0 * Some changes. '''; plugin.changelogFile.writeAsStringSync(changelog); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin/lib/plugin.dart packages/plugin/CHANGELOG.md packages/plugin/pubspec.yaml -''')), - ]; - - final List output = - await runWithMissingChangeDetection([ - '--pr-labels=some label,override: no versioning needed,another-label' +''', + ), + ), + ]; + + final List + output = await runWithMissingChangeDetection([ + '--pr-labels=some label,override: no versioning needed,another-label', ]); expect( output, containsAllInOrder([ - contains('Ignoring lack of version change due to the ' - '"override: no versioning needed" label.'), + contains( + 'Ignoring lack of version change due to the ' + '"override: no versioning needed" label.', + ), ]), ); }); test('fails if a CHANGELOG change is missing', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.0'); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.0', + ); - const String changelog = ''' + const changelog = ''' ## 1.0.0 * Some changes. '''; plugin.changelogFile.writeAsStringSync(changelog); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin/example/lib/foo.dart -''')), - ]; +''', + ), + ), + ]; Error? commandError; final List output = await runWithMissingChangeDetection( - [], errorHandler: (Error e) { - commandError = e; - }); + [], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( output, containsAllInOrder([ contains('No CHANGELOG change found.\nIf'), - contains('plugin:\n' - ' Missing CHANGELOG change'), + contains( + 'plugin:\n' + ' Missing CHANGELOG change', + ), ]), ); }); test('passes CHANGELOG check when the CHANGELOG is changed', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.0'); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.0', + ); - const String changelog = ''' + const changelog = ''' ## 1.0.0 * Some changes. '''; plugin.changelogFile.writeAsStringSync(changelog); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin/example/lib/foo.dart packages/plugin/CHANGELOG.md -''')), - ]; +''', + ), + ), + ]; - final List output = - await runWithMissingChangeDetection([]); + final List output = await runWithMissingChangeDetection( + [], + ); expect( output, - containsAllInOrder([ - contains('Running for plugin'), - ]), + containsAllInOrder([contains('Running for plugin')]), ); }); - test('fails CHANGELOG check if only another package CHANGELOG chages', - () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.0'); + test( + 'fails CHANGELOG check if only another package CHANGELOG chages', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.0', + ); - const String changelog = ''' + const changelog = ''' ## 1.0.0 * Some changes. '''; - plugin.changelogFile.writeAsStringSync(changelog); - gitProcessRunner.mockProcessesForExecutable['git-show'] = - [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: ''' + plugin.changelogFile.writeAsStringSync(changelog); + gitProcessRunner.mockProcessesForExecutable['git-show'] = + [ + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; + gitProcessRunner.mockProcessesForExecutable['git-diff'] = + [ + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin/example/lib/foo.dart packages/another_plugin/CHANGELOG.md -''')), - ]; - - Error? commandError; - final List output = await runWithMissingChangeDetection( - [], errorHandler: (Error e) { - commandError = e; - }); +''', + ), + ), + ]; + + Error? commandError; + final List output = await runWithMissingChangeDetection( + [], + errorHandler: (Error e) { + commandError = e; + }, + ); - expect(commandError, isA()); - expect( - output, - containsAllInOrder([ - contains('No CHANGELOG change found'), - ]), - ); - }); + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains('No CHANGELOG change found'), + ]), + ); + }, + ); test('allows missing CHANGELOG change with justification', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.0'); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.0', + ); - const String changelog = ''' + const changelog = ''' ## 1.0.0 * Some changes. '''; plugin.changelogFile.writeAsStringSync(changelog); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; gitProcessRunner.mockProcessesForExecutable['git-diff'] = [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin/example/lib/foo.dart -''')), - ]; - - final List output = - await runWithMissingChangeDetection([ - '--pr-labels=some label,override: no changelog needed,another-label' +''', + ), + ), + ]; + + final List + output = await runWithMissingChangeDetection([ + '--pr-labels=some label,override: no changelog needed,another-label', ]); expect( output, containsAllInOrder([ - contains('Ignoring lack of CHANGELOG update due to the ' - '"override: no changelog needed" label.'), + contains( + 'Ignoring lack of CHANGELOG update due to the ' + '"override: no changelog needed" label.', + ), ]), ); }); @@ -1109,149 +1318,194 @@ packages/plugin/example/lib/foo.dart // This test ensures that Dependabot Gradle changes to test-only files // aren't flagged by the version check. test( - 'allows missing CHANGELOG and version change for test-only Gradle changes', - () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.0'); + 'allows missing CHANGELOG and version change for test-only Gradle changes', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.0', + ); - const String changelog = ''' + const changelog = ''' ## 1.0.0 * Some changes. '''; - plugin.changelogFile.writeAsStringSync(changelog); - gitProcessRunner.mockProcessesForExecutable['git-show'] = - [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - // File list. - FakeProcessInfo(MockProcess(stdout: ''' + plugin.changelogFile.writeAsStringSync(changelog); + gitProcessRunner.mockProcessesForExecutable['git-show'] = + [ + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; + gitProcessRunner.mockProcessesForExecutable['git-diff'] = + [ + // File list. + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin/android/build.gradle -''')), - // build.gradle diff - FakeProcessInfo(MockProcess(stdout: ''' +''', + ), + ), + // build.gradle diff + FakeProcessInfo( + MockProcess( + stdout: ''' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' - testImplementation 'junit:junit:4.10.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + testImplementation 'junit:junit:4.13.2' -''')), - ]; +''', + ), + ), + ]; - final List output = - await runWithMissingChangeDetection([]); + final List output = await runWithMissingChangeDetection( + [], + ); - expect( - output, - containsAllInOrder([ - contains('Running for plugin'), - ]), - ); - }); + expect( + output, + containsAllInOrder([contains('Running for plugin')]), + ); + }, + ); test( - 'allows missing CHANGELOG and version change for dev-only-file changes', - () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.0'); + 'allows missing CHANGELOG and version change for dev-only-file changes', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.0', + ); - const String changelog = ''' + const changelog = ''' ## 1.0.0 * Some changes. '''; - plugin.changelogFile.writeAsStringSync(changelog); - gitProcessRunner.mockProcessesForExecutable['git-show'] = - [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - // File list. - FakeProcessInfo(MockProcess(stdout: ''' + plugin.changelogFile.writeAsStringSync(changelog); + gitProcessRunner.mockProcessesForExecutable['git-show'] = + [ + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; + gitProcessRunner.mockProcessesForExecutable['git-diff'] = + [ + // File list. + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin/tool/run_tests.dart packages/plugin/run_tests.sh -''')), - ]; +''', + ), + ), + ]; - final List output = - await runWithMissingChangeDetection([]); + final List output = await runWithMissingChangeDetection( + [], + ); - expect( - output, - containsAllInOrder([ - contains('Running for plugin'), - ]), - ); - }); + expect( + output, + containsAllInOrder([contains('Running for plugin')]), + ); + }, + ); test( - 'allows missing CHANGELOG and version change for dev-only line-level ' - 'changes in production files', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.0'); + 'allows missing CHANGELOG and version change for dev-only line-level ' + 'changes in production files', + () async { + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.0', + ); - const String changelog = ''' + const changelog = ''' ## 1.0.0 * Some changes. '''; - plugin.changelogFile.writeAsStringSync(changelog); - gitProcessRunner.mockProcessesForExecutable['git-show'] = - [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - // File list. - FakeProcessInfo(MockProcess(stdout: ''' + plugin.changelogFile.writeAsStringSync(changelog); + gitProcessRunner.mockProcessesForExecutable['git-show'] = + [ + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; + gitProcessRunner + .mockProcessesForExecutable['git-diff'] = [ + // File list. + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin/lib/plugin.dart -''')), - // Dart file diff. - FakeProcessInfo(MockProcess(stdout: ''' +''', + ), + ), + // Dart file diff. + FakeProcessInfo( + MockProcess( + stdout: ''' + // TODO(someone): Fix this. + // ignore: some_lint -'''), ['main', 'HEAD', '--', 'packages/plugin/lib/plugin.dart']), - ]; +''', + ), + ['main', 'HEAD', '--', 'packages/plugin/lib/plugin.dart'], + ), + ]; - final List output = - await runWithMissingChangeDetection([]); + final List output = await runWithMissingChangeDetection( + [], + ); - expect( - output, - containsAllInOrder([ - contains('Running for plugin'), - ]), - ); - }); + expect( + output, + containsAllInOrder([contains('Running for plugin')]), + ); + }, + ); test('documentation comments are not exempt', () async { - final RepositoryPackage plugin = - createFakePlugin('plugin', packagesDir, version: '1.0.0'); + final RepositoryPackage plugin = createFakePlugin( + 'plugin', + packagesDir, + version: '1.0.0', + ); - const String changelog = ''' + const changelog = ''' ## 1.0.0 * Some changes. '''; plugin.changelogFile.writeAsStringSync(changelog); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; - gitProcessRunner.mockProcessesForExecutable['git-diff'] = - [ - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; + gitProcessRunner + .mockProcessesForExecutable['git-diff'] = [ + FakeProcessInfo( + MockProcess( + stdout: ''' packages/plugin/lib/plugin.dart -''')), +''', + ), + ), // Dart file diff. - FakeProcessInfo(MockProcess(stdout: ''' + FakeProcessInfo( + MockProcess( + stdout: ''' + /// Important new information for API clients! -'''), ['main', 'HEAD', '--', 'packages/plugin/lib/plugin.dart']), +''', + ), + ['main', 'HEAD', '--', 'packages/plugin/lib/plugin.dart'], + ), ]; Error? commandError; final List output = await runWithMissingChangeDetection( - [], errorHandler: (Error e) { - commandError = e; - }); + [], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( @@ -1261,8 +1515,10 @@ packages/plugin/lib/plugin.dart 'No version change found, but the change to this package could ' 'not be verified to be exempt\n', ), - contains('plugin:\n' - ' Missing version change'), + contains( + 'plugin:\n' + ' Missing version change', + ), ]), ); }); @@ -1271,16 +1527,15 @@ packages/plugin/lib/plugin.dart test('allows valid against pub', () async { mockHttpResponse = { 'name': 'some_package', - 'versions': [ - '0.0.1', - '0.0.2', - '1.0.0', - ], + 'versions': ['0.0.1', '0.0.2', '1.0.0'], }; createFakePlugin('plugin', packagesDir, version: '2.0.0'); - final List output = await runCapturingPrint(runner, - ['version-check', '--base-sha=main', '--against-pub']); + final List output = await runCapturingPrint(runner, [ + 'version-check', + '--base-sha=main', + '--against-pub', + ]); expect( output, @@ -1293,116 +1548,132 @@ packages/plugin/lib/plugin.dart test('denies invalid against pub', () async { mockHttpResponse = { 'name': 'some_package', - 'versions': [ - '0.0.1', - '0.0.2', - ], + 'versions': ['0.0.1', '0.0.2'], }; createFakePlugin('plugin', packagesDir, version: '2.0.0'); - bool hasError = false; + var hasError = false; final List result = await runCapturingPrint( - runner, ['version-check', '--base-sha=main', '--against-pub'], - errorHandler: (Error e) { - expect(e, isA()); - hasError = true; - }); + runner, + ['version-check', '--base-sha=main', '--against-pub'], + errorHandler: (Error e) { + expect(e, isA()); + hasError = true; + }, + ); expect(hasError, isTrue); expect( result, containsAllInOrder([ - contains(''' + contains( + ''' ${indentation}Incorrectly updated version. ${indentation}HEAD: 2.0.0, pub: 0.0.2. -${indentation}Allowed versions: {1.0.0: NextVersionType.BREAKING_MAJOR, 0.1.0: NextVersionType.MINOR, 0.0.3: NextVersionType.PATCH}''') +${indentation}Allowed versions: {1.0.0: NextVersionType.BREAKING_MAJOR, 0.1.0: NextVersionType.MINOR, 0.0.3: NextVersionType.PATCH}''', + ), ]), ); }); test( - 'throw and print error message if http request failed when checking against pub', - () async { - mockHttpStatus = 400; + 'throw and print error message if http request failed when checking against pub', + () async { + mockHttpStatus = 400; - createFakePlugin('plugin', packagesDir, version: '2.0.0'); - bool hasError = false; - final List result = await runCapturingPrint( - runner, ['version-check', '--base-sha=main', '--against-pub'], + createFakePlugin('plugin', packagesDir, version: '2.0.0'); + var hasError = false; + final List result = await runCapturingPrint( + runner, + ['version-check', '--base-sha=main', '--against-pub'], errorHandler: (Error e) { - expect(e, isA()); - hasError = true; - }); - expect(hasError, isTrue); + expect(e, isA()); + hasError = true; + }, + ); + expect(hasError, isTrue); - expect( - result, - containsAllInOrder([ - contains(''' + expect( + result, + containsAllInOrder([ + contains(''' ${indentation}Error fetching version on pub for plugin. ${indentation}HTTP Status 400 ${indentation}HTTP response: null -''') - ]), - ); - }); - - test('when checking against pub, allow any version if http status is 404.', - () async { - mockHttpStatus = 404; - - createFakePlugin('plugin', packagesDir, version: '2.0.0'); - gitProcessRunner.mockProcessesForExecutable['git-show'] = - [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; - final List result = await runCapturingPrint(runner, - ['version-check', '--base-sha=main', '--against-pub']); +'''), + ]), + ); + }, + ); - expect( - result, - containsAllInOrder([ - contains('Unable to find previous version on pub server.'), - ]), - ); - }); + test( + 'when checking against pub, allow any version if http status is 404.', + () async { + mockHttpStatus = 404; - group('prelease versions', () { - test( - 'allow an otherwise-valid transition that also adds a pre-release component', - () async { - createFakePlugin('plugin', packagesDir, version: '2.0.0-dev'); + createFakePlugin('plugin', packagesDir, version: '2.0.0'); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), - ]; - final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main']); + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; + final List result = await runCapturingPrint(runner, [ + 'version-check', + '--base-sha=main', + '--against-pub', + ]); expect( - output, + result, containsAllInOrder([ - contains('Running for plugin'), - contains('1.0.0 -> 2.0.0-dev'), + contains('Unable to find previous version on pub server.'), ]), ); - expect( + }, + ); + + group('prelease versions', () { + test( + 'allow an otherwise-valid transition that also adds a pre-release component', + () async { + createFakePlugin('plugin', packagesDir, version: '2.0.0-dev'); + gitProcessRunner.mockProcessesForExecutable['git-show'] = + [ + FakeProcessInfo(MockProcess(stdout: 'version: 1.0.0')), + ]; + final List output = await runCapturingPrint(runner, [ + 'version-check', + '--base-sha=main', + ]); + + expect( + output, + containsAllInOrder([ + contains('Running for plugin'), + contains('1.0.0 -> 2.0.0-dev'), + ]), + ); + expect( gitProcessRunner.recordedCalls, containsAllInOrder(const [ - ProcessCall('git-show', - ['main:packages/plugin/pubspec.yaml'], null) - ])); - }); + ProcessCall('git-show', [ + 'main:packages/plugin/pubspec.yaml', + ], null), + ]), + ); + }, + ); test('allow releasing a pre-release', () async { createFakePlugin('plugin', packagesDir, version: '1.2.0'); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.2.0-dev')), - ]; - final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main']); + FakeProcessInfo(MockProcess(stdout: 'version: 1.2.0-dev')), + ]; + final List output = await runCapturingPrint(runner, [ + 'version-check', + '--base-sha=main', + ]); expect( output, @@ -1412,49 +1683,58 @@ ${indentation}HTTP response: null ]), ); expect( - gitProcessRunner.recordedCalls, - containsAllInOrder(const [ - ProcessCall('git-show', - ['main:packages/plugin/pubspec.yaml'], null) - ])); + gitProcessRunner.recordedCalls, + containsAllInOrder(const [ + ProcessCall('git-show', [ + 'main:packages/plugin/pubspec.yaml', + ], null), + ]), + ); }); // Allow abandoning a pre-release version in favor of a different version // change type. test( - 'allow an otherwise-valid transition that also removes a pre-release component', - () async { - createFakePlugin('plugin', packagesDir, version: '2.0.0'); - gitProcessRunner.mockProcessesForExecutable['git-show'] = - [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.2.0-dev')), - ]; - final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main']); - - expect( - output, - containsAllInOrder([ - contains('Running for plugin'), - contains('1.2.0-dev -> 2.0.0'), - ]), - ); - expect( + 'allow an otherwise-valid transition that also removes a pre-release component', + () async { + createFakePlugin('plugin', packagesDir, version: '2.0.0'); + gitProcessRunner.mockProcessesForExecutable['git-show'] = + [ + FakeProcessInfo(MockProcess(stdout: 'version: 1.2.0-dev')), + ]; + final List output = await runCapturingPrint(runner, [ + 'version-check', + '--base-sha=main', + ]); + + expect( + output, + containsAllInOrder([ + contains('Running for plugin'), + contains('1.2.0-dev -> 2.0.0'), + ]), + ); + expect( gitProcessRunner.recordedCalls, containsAllInOrder(const [ - ProcessCall('git-show', - ['main:packages/plugin/pubspec.yaml'], null) - ])); - }); + ProcessCall('git-show', [ + 'main:packages/plugin/pubspec.yaml', + ], null), + ]), + ); + }, + ); test('allow changing only the pre-release version', () async { createFakePlugin('plugin', packagesDir, version: '1.2.0-dev.2'); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 1.2.0-dev.1')), - ]; - final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main']); + FakeProcessInfo(MockProcess(stdout: 'version: 1.2.0-dev.1')), + ]; + final List output = await runCapturingPrint(runner, [ + 'version-check', + '--base-sha=main', + ]); expect( output, @@ -1464,104 +1744,131 @@ ${indentation}HTTP response: null ]), ); expect( - gitProcessRunner.recordedCalls, - containsAllInOrder(const [ - ProcessCall('git-show', - ['main:packages/plugin/pubspec.yaml'], null) - ])); + gitProcessRunner.recordedCalls, + containsAllInOrder(const [ + ProcessCall('git-show', [ + 'main:packages/plugin/pubspec.yaml', + ], null), + ]), + ); }); - test('denies invalid version change that also adds a pre-release', - () async { - createFakePlugin('plugin', packagesDir, version: '0.2.0-dev'); - gitProcessRunner.mockProcessesForExecutable['git-show'] = - [ - FakeProcessInfo(MockProcess(stdout: 'version: 0.0.1')), - ]; - Error? commandError; - final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main'], + test( + 'denies invalid version change that also adds a pre-release', + () async { + createFakePlugin('plugin', packagesDir, version: '0.2.0-dev'); + gitProcessRunner.mockProcessesForExecutable['git-show'] = + [ + FakeProcessInfo(MockProcess(stdout: 'version: 0.0.1')), + ]; + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['version-check', '--base-sha=main'], errorHandler: (Error e) { - commandError = e; - }); + commandError = e; + }, + ); - expect(commandError, isA()); - expect( + expect(commandError, isA()); + expect( output, containsAllInOrder([ contains('Incorrectly updated version.'), - ])); - expect( + ]), + ); + expect( gitProcessRunner.recordedCalls, containsAllInOrder(const [ - ProcessCall('git-show', - ['main:packages/plugin/pubspec.yaml'], null) - ])); - }); + ProcessCall('git-show', [ + 'main:packages/plugin/pubspec.yaml', + ], null), + ]), + ); + }, + ); - test('denies invalid version change that also removes a pre-release', - () async { - createFakePlugin('plugin', packagesDir, version: '0.2.0'); - gitProcessRunner.mockProcessesForExecutable['git-show'] = - [ - FakeProcessInfo(MockProcess(stdout: 'version: 0.0.1-dev')), - ]; - Error? commandError; - final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main'], + test( + 'denies invalid version change that also removes a pre-release', + () async { + createFakePlugin('plugin', packagesDir, version: '0.2.0'); + gitProcessRunner.mockProcessesForExecutable['git-show'] = + [ + FakeProcessInfo(MockProcess(stdout: 'version: 0.0.1-dev')), + ]; + Error? commandError; + final List output = await runCapturingPrint( + runner, + ['version-check', '--base-sha=main'], errorHandler: (Error e) { - commandError = e; - }); + commandError = e; + }, + ); - expect(commandError, isA()); - expect( + expect(commandError, isA()); + expect( output, containsAllInOrder([ contains('Incorrectly updated version.'), - ])); - expect( + ]), + ); + expect( gitProcessRunner.recordedCalls, containsAllInOrder(const [ - ProcessCall('git-show', - ['main:packages/plugin/pubspec.yaml'], null) - ])); - }); + ProcessCall('git-show', [ + 'main:packages/plugin/pubspec.yaml', + ], null), + ]), + ); + }, + ); test('denies invalid version change between pre-releases', () async { createFakePlugin('plugin', packagesDir, version: '0.2.0-dev'); gitProcessRunner.mockProcessesForExecutable['git-show'] = [ - FakeProcessInfo(MockProcess(stdout: 'version: 0.0.1-dev')), - ]; + FakeProcessInfo(MockProcess(stdout: 'version: 0.0.1-dev')), + ]; Error? commandError; final List output = await runCapturingPrint( - runner, ['version-check', '--base-sha=main'], - errorHandler: (Error e) { - commandError = e; - }); + runner, + ['version-check', '--base-sha=main'], + errorHandler: (Error e) { + commandError = e; + }, + ); expect(commandError, isA()); expect( - output, - containsAllInOrder([ - contains('Incorrectly updated version.'), - ])); + output, + containsAllInOrder([ + contains('Incorrectly updated version.'), + ]), + ); expect( - gitProcessRunner.recordedCalls, - containsAllInOrder(const [ - ProcessCall('git-show', - ['main:packages/plugin/pubspec.yaml'], null) - ])); + gitProcessRunner.recordedCalls, + containsAllInOrder(const [ + ProcessCall('git-show', [ + 'main:packages/plugin/pubspec.yaml', + ], null), + ]), + ); }); }); }); group('Pre 1.0', () { test('nextVersion allows patch version', () { - testAllowedVersion('0.12.0', '0.12.0+1', - nextVersionType: NextVersionType.PATCH); - testAllowedVersion('0.12.0+4', '0.12.0+5', - nextVersionType: NextVersionType.PATCH); + testAllowedVersion( + '0.12.0', + '0.12.0+1', + nextVersionType: NextVersionType.PATCH, + ); + testAllowedVersion( + '0.12.0+4', + '0.12.0+5', + nextVersionType: NextVersionType.PATCH, + ); }); test('nextVersion does not allow jumping patch', () { @@ -1576,10 +1883,16 @@ ${indentation}HTTP response: null }); test('nextVersion allows minor version', () { - testAllowedVersion('0.12.0', '0.12.1', - nextVersionType: NextVersionType.MINOR); - testAllowedVersion('0.12.0+4', '0.12.1', - nextVersionType: NextVersionType.MINOR); + testAllowedVersion( + '0.12.0', + '0.12.1', + nextVersionType: NextVersionType.MINOR, + ); + testAllowedVersion( + '0.12.0+4', + '0.12.1', + nextVersionType: NextVersionType.MINOR, + ); }); test('nextVersion does not allow jumping minor', () { @@ -1590,10 +1903,16 @@ ${indentation}HTTP response: null group('Releasing 1.0', () { test('nextVersion allows releasing 1.0', () { - testAllowedVersion('0.12.0', '1.0.0', - nextVersionType: NextVersionType.BREAKING_MAJOR); - testAllowedVersion('0.12.0+4', '1.0.0', - nextVersionType: NextVersionType.BREAKING_MAJOR); + testAllowedVersion( + '0.12.0', + '1.0.0', + nextVersionType: NextVersionType.BREAKING_MAJOR, + ); + testAllowedVersion( + '0.12.0+4', + '1.0.0', + nextVersionType: NextVersionType.BREAKING_MAJOR, + ); }); test('nextVersion does not allow jumping major', () { @@ -1609,10 +1928,16 @@ ${indentation}HTTP response: null group('Post 1.0', () { test('nextVersion allows patch jumps', () { - testAllowedVersion('1.0.1', '1.0.2', - nextVersionType: NextVersionType.PATCH); - testAllowedVersion('1.0.0', '1.0.1', - nextVersionType: NextVersionType.PATCH); + testAllowedVersion( + '1.0.1', + '1.0.2', + nextVersionType: NextVersionType.PATCH, + ); + testAllowedVersion( + '1.0.0', + '1.0.1', + nextVersionType: NextVersionType.PATCH, + ); }); test('nextVersion does not allow build jumps', () { @@ -1626,10 +1951,16 @@ ${indentation}HTTP response: null }); test('nextVersion allows minor version jumps', () { - testAllowedVersion('1.0.1', '1.1.0', - nextVersionType: NextVersionType.MINOR); - testAllowedVersion('1.0.0', '1.1.0', - nextVersionType: NextVersionType.MINOR); + testAllowedVersion( + '1.0.1', + '1.1.0', + nextVersionType: NextVersionType.MINOR, + ); + testAllowedVersion( + '1.0.0', + '1.1.0', + nextVersionType: NextVersionType.MINOR, + ); }); test('nextVersion does not allow skipping minor versions', () { @@ -1638,10 +1969,16 @@ ${indentation}HTTP response: null }); test('nextVersion allows breaking changes', () { - testAllowedVersion('1.0.1', '2.0.0', - nextVersionType: NextVersionType.BREAKING_MAJOR); - testAllowedVersion('1.0.0', '2.0.0', - nextVersionType: NextVersionType.BREAKING_MAJOR); + testAllowedVersion( + '1.0.1', + '2.0.0', + nextVersionType: NextVersionType.BREAKING_MAJOR, + ); + testAllowedVersion( + '1.0.0', + '2.0.0', + nextVersionType: NextVersionType.BREAKING_MAJOR, + ); }); test('nextVersion does not allow skipping major versions', () {