From 0acf53e3108b2ab0739e2b5e458dc113b94f65a7 Mon Sep 17 00:00:00 2001 From: Ian Hickson <ian@hixie.ch> Date: Fri, 4 Jun 2021 01:09:02 -0700 Subject: [PATCH] Run `dart fix` on customer tests as promised (#83944) --- dev/customer_testing/lib/runner.dart | 114 ++++++++++++++++++--------- dev/customer_testing/run_tests.dart | 28 +++++-- 2 files changed, 96 insertions(+), 46 deletions(-) diff --git a/dev/customer_testing/lib/runner.dart b/dev/customer_testing/lib/runner.dart index 79736a77bb..58e00ca26d 100644 --- a/dev/customer_testing/lib/runner.dart +++ b/dev/customer_testing/lib/runner.dart @@ -31,13 +31,21 @@ Future<bool> runTests({ if (verbose) { final String s = files.length == 1 ? '' : 's'; - final String ss = shardedFiles.length == 1 ? '' : 's'; - print('${files.length} file$s specified. ${shardedFiles.length} test$ss in shard #$shardIndex.'); + if (numberShards > 1) { + final String ss = shardedFiles.length == 1 ? '' : 's'; + print('${files.length} file$s specified. ${shardedFiles.length} test$ss in shard #$shardIndex ($numberShards shards total).'); + } else { + print('${files.length} file$s specified.'); + } print(''); } if (verbose) { - print('Tests in this shard:'); + if (numberShards > 1) { + print('Tests in this shard:'); + } else { + print('Tests:'); + } for (final File file in shardedFiles) print(file.path); } @@ -46,30 +54,40 @@ Future<bool> runTests({ for (final File file in shardedFiles) { if (verbose) print('Processing ${file.path}...'); + + void printHeader() { + if (!verbose) + print('Processing ${file.path}...'); + } + + void failure(String message) { + printHeader(); + print('ERROR: $message'); + failures += 1; + } + CustomerTest instructions; try { instructions = CustomerTest(file); } on FormatException catch (error) { - print('ERROR: ${error.message}'); + failure(error.message); print(''); - failures += 1; continue; } on FileSystemException catch (error) { - print('ERROR: ${error.message}'); - print(' ${file.path}'); + failure(error.message); print(''); - failures += 1; continue; } + bool success = true; + final Directory checkout = Directory.systemTemp.createTempSync('flutter_customer_testing.${path.basenameWithoutExtension(file.path)}.'); if (verbose) print('Created temporary directory: ${checkout.path}'); try { - bool? success; - bool showContacts = false; + assert(instructions.fetch.isNotEmpty); for (final String fetchCommand in instructions.fetch) { - success = await shell(fetchCommand, checkout, verbose: verbose, silentFailure: skipOnFetchFailure); + success = await shell(fetchCommand, checkout, verbose: verbose, silentFailure: skipOnFetchFailure, failedCallback: printHeader); if (!success) { if (skipOnFetchFailure) { if (verbose) { @@ -78,39 +96,51 @@ Future<bool> runTests({ print('Skipping ${file.path} (fetch failed).'); } } else { - print('ERROR: Failed to fetch repository.'); - failures += 1; - showContacts = true; + failure('Failed to fetch repository.'); } break; } } - assert(success != null); - if (success == true) { - if (verbose) - print('Running tests...'); - final Directory tests = Directory(path.join(checkout.path, 'tests')); - // TODO(ianh): Once we have a way to update source code, run that command in each directory of instructions.update - for (int iteration = 0; iteration < repeat; iteration += 1) { - if (verbose && repeat > 1) - print('Round ${iteration + 1} of $repeat.'); - for (final String testCommand in instructions.tests) { - testCount += 1; - success = await shell(testCommand, tests, verbose: verbose); - if (!success) { - print('ERROR: One or more tests from ${path.basenameWithoutExtension(file.path)} failed.'); - failures += 1; - showContacts = true; - break; + if (success) { + final Directory customerRepo = Directory(path.join(checkout.path, 'tests')); + for (final Directory updateDirectory in instructions.update) { + final Directory resolvedUpdateDirectory = Directory(path.join(customerRepo.path, updateDirectory.path)); + if (verbose) + print('Updating code in ${resolvedUpdateDirectory.path}...'); + if (!File(path.join(resolvedUpdateDirectory.path, 'pubspec.yaml')).existsSync()) { + failure('The directory ${updateDirectory.path}, which was specified as an update directory, does not contain a "pubspec.yaml" file.'); + success = false; + break; + } + success = await shell('flutter packages get', resolvedUpdateDirectory, verbose: verbose, failedCallback: printHeader); + if (!success) { + failure('Could not run "flutter pub get" in ${updateDirectory.path}, which was specified as an update directory.'); + break; + } + success = await shell('dart fix --apply', resolvedUpdateDirectory, verbose: verbose, failedCallback: printHeader); + if (!success) { + failure('Could not run "dart fix" in ${updateDirectory.path}, which was specified as an update directory.'); + break; + } + } + if (success) { + if (verbose) + print('Running tests...'); + for (int iteration = 0; iteration < repeat; iteration += 1) { + if (verbose && repeat > 1) + print('Round ${iteration + 1} of $repeat.'); + for (final String testCommand in instructions.tests) { + testCount += 1; + success = await shell(testCommand, customerRepo, verbose: verbose, failedCallback: printHeader); + if (!success) { + failure('One or more tests from ${path.basenameWithoutExtension(file.path)} failed.'); + break; + } } } + if (verbose && success) + print('Tests finished.'); } - if (verbose && success == true) - print('Tests finished.'); - } - if (showContacts) { - final String s = instructions.contacts.length == 1 ? '' : 's'; - print('Contact$s: ${instructions.contacts.join(", ")}'); } } finally { if (verbose) @@ -121,7 +151,11 @@ Future<bool> runTests({ print('Failed to delete "${checkout.path}".'); } } - if (verbose) + if (!success) { + final String s = instructions.contacts.length == 1 ? '' : 's'; + print('Contact$s: ${instructions.contacts.join(", ")}'); + } + if (verbose || !success) print(''); } if (failures > 0) { @@ -135,7 +169,7 @@ Future<bool> runTests({ final RegExp _spaces = RegExp(r' +'); -Future<bool> shell(String command, Directory directory, { bool verbose = false, bool silentFailure = false }) async { +Future<bool> shell(String command, Directory directory, { bool verbose = false, bool silentFailure = false, void Function()? failedCallback }) async { if (verbose) print('>> $command'); Process process; @@ -152,6 +186,8 @@ Future<bool> shell(String command, Directory directory, { bool verbose = false, if (success || silentFailure) return success; if (!verbose) { + if (failedCallback != null) + failedCallback(); print('>> $command'); output.forEach(printLog); } diff --git a/dev/customer_testing/run_tests.dart b/dev/customer_testing/run_tests.dart index dbc2d63c6d..c792722a8b 100644 --- a/dev/customer_testing/run_tests.dart +++ b/dev/customer_testing/run_tests.dart @@ -15,6 +15,7 @@ Future<void> main(List<String> arguments) async { exit(await run(arguments) ? 0 : 1); } +// Return true if successful, false if failed. Future<bool> run(List<String> arguments) async { final ArgParser argParser = ArgParser( allowTrailingOptions: false, @@ -92,11 +93,21 @@ Future<bool> run(List<String> arguments) async { .where((File file) => !skipTemplate || path.basename(file.path) != 'template.test') .toList(); - if (help || repeat == null || files.isEmpty) { + if (help || repeat == null || files.isEmpty || numberShards == null || numberShards <= 0 || shardIndex == null || shardIndex < 0) { printHelp(); if (verbose) { if (repeat == null) print('Error: Could not parse repeat count ("${parsedArguments['repeat']}")'); + if (numberShards == null) { + print('Error: Could not parse shards count ("${parsedArguments['shards']}")'); + } else if (numberShards < 1) { + print('Error: The specified shards count ($numberShards) is less than 1. It must be greater than zero.'); + } + if (shardIndex == null) { + print('Error: Could not parse shard index ("${parsedArguments['shard-index']}")'); + } else if (shardIndex < 0) { + print('Error: The specified shard index ($shardIndex) is negative. It must be in the range [0 .. shards - 1].'); + } if (parsedArguments.rest.isEmpty) { print('Error: No file arguments specified.'); } else if (files.isEmpty) { @@ -106,14 +117,17 @@ Future<bool> run(List<String> arguments) async { return help; } - if (files.length < shardIndex!) - print('Warning: There are more shards than tests. Some shards will not run any tests.'); - - if (numberShards! <= shardIndex) { - print('Error: There are more shard indexes than shards.'); - return help; + if (shardIndex > numberShards - 1) { + print( + 'Error: The specified shard index ($shardIndex) is more than the specified number of shards ($numberShards). ' + 'It must be in the range [0 .. shards - 1].' + ); + return false; } + if (files.length < numberShards) + print('Warning: There are more shards than tests. Some shards will not run any tests.'); + return runTests( repeat: repeat, skipOnFetchFailure: skipOnFetchFailure, -- 2.21.0