run method
Runs this command.
The return value is wrapped in a Future
if necessary and returned by
CommandRunner.runCommand
.
Implementation
@override
Future<ExitCode> run([List<String>? args]) async {
final argResults = args != null ? argParser.parse(args) : super.argResults!;
final isDartOnly =
argResults.wasParsed('dart-only') && argResults['dart-only'] as bool;
final isFlutterOnly = argResults.wasParsed('flutter-only') &&
argResults['flutter-only'] as bool;
final isBoth = isDartOnly == isFlutterOnly;
final optimize = argResults['optimize'] as bool;
final isRecursive = argResults['recursive'] as bool? ?? false;
final cleanOptimizedFiles = argResults['clean'] as bool;
final providedTests = [...argResults.rest];
List<String>? testsToRun;
if (providedTests.isNotEmpty) {
testsToRun = getTestsFromProvided(providedTests);
if (testsToRun.isEmpty) {
logger.err('No valid files or directories found');
return ExitCode.usage;
}
}
if (isRecursive && testsToRun != null) {
logger.err(
'Cannot run tests recursively with specific files or directories',
);
return ExitCode.usage;
}
warnDartOrFlutterTests(
isFlutterOnly: isFlutterOnly,
isDartOnly: isDartOnly,
);
if (isRecursive) {
logger.detail('Running tests recursively');
}
final pubspecs = await pubspecYaml.all(recursive: isRecursive);
if (pubspecs.isEmpty) {
logger.err('No pubspec.yaml files found');
return ExitCode.unavailable;
}
final (:both, :dart, :flutter) = getArgs(this);
final flutterArgs = [...flutter, ...both];
final dartArgs = [...dart, ...both];
final commandsToRun = <CommandToRun>[];
void Function()? cleanUp;
if (testsToRun != null) {
final pubspec = pubspecYaml.nearest();
if (pubspec == null) {
logger.err('No pubspec.yaml file found');
return ExitCode.unavailable;
}
final tool = DetermineFlutterOrDart(
pubspecYaml: pubspec,
pubspecLock: pubspecLock,
findFile: findFile,
);
final command = createTestCommand(
projectRoot: tool.directory(),
relativeProjectRoot: path.relative(tool.directory()),
tool: tool,
flutterArgs: flutterArgs,
dartArgs: dartArgs,
tests: testsToRun,
);
commandsToRun.add(command);
} else {
final (dirs, dirExitCode) = getTestDirs(
pubspecs,
isFlutterOnly: isFlutterOnly,
isDartOnly: isDartOnly,
);
// exit code is not null
if (dirExitCode case final ExitCode exitCode) {
return exitCode;
} else if (dirs == null) {
logger.err('No tests found');
return ExitCode.unavailable;
}
final (testDirs, dirTools) = dirs;
logger.detail('Found ${testDirs.length} test directories');
logger.detail(' - ${testDirs.join('\n - ')}');
final (tests, testsExitCode) = getPackagesToTest(
testDirs,
dirTools,
optimize: optimize,
);
// exit code is not null
if (testsExitCode case final ExitCode exitCode) {
return exitCode;
} else if (tests == null) {
logger.err('No tests found');
return ExitCode.unavailable;
}
commandsToRun.addAll(
getCommandsToRun(
tests,
flutterArgs: flutterArgs,
dartArgs: dartArgs,
),
);
cleanUp = () => cleanUpOptimizedFiles(tests.map((e) => e.optimizedPath));
}
logger.info('ARGS:');
if (isBoth || isDartOnly) {
var message = darkGray.wrap(' Dart: ')!;
if (dartArgs.isEmpty) {
message += cyan.wrap('NONE')!;
} else {
message += cyan.wrap(dartArgs.join(', '))!;
}
logger.info(message);
}
if (isBoth || isFlutterOnly) {
var message = darkGray.wrap(' Flutter: ')!;
if (flutterArgs.isEmpty) {
message += cyan.wrap('NONE')!;
} else {
message += cyan.wrap(flutterArgs.join(', '))!;
}
logger.info(message);
}
logger.write('\n');
final exitCode = await runCommands(
commandsToRun,
runConcurrently: argResults['concurrent'] as bool,
bail: argResults['bail'] as bool,
);
logger.write('\n');
if (optimize && cleanOptimizedFiles) {
final done = logger.progress('Cleaning up optimized test files');
cleanUp?.call();
done.complete('Optimized test files cleaned!');
}
if (exitCode != ExitCode.success) {
logger.err('${red.wrap('✗')} Some tests failed');
} else {
logger.write('${green.wrap('✔')} Tests passed');
}
logger.write('\n');
return exitCode;
}