-
Notifications
You must be signed in to change notification settings - Fork 55
[coverage] Partial workspace support #2095
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b84b3be
7929258
a698428
63f464f
54d58ce
4679769
55fc13c
63bd880
830a8d6
295a168
733de72
6d5cc8d
4d60c70
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,10 +7,8 @@ import 'dart:io'; | |
|
||
import 'package:args/args.dart'; | ||
import 'package:coverage/src/coverage_options.dart'; | ||
import 'package:coverage/src/util.dart' | ||
show StandardOutExtension, extractVMServiceUri; | ||
import 'package:coverage/src/util.dart'; | ||
import 'package:meta/meta.dart'; | ||
import 'package:package_config/package_config.dart'; | ||
import 'package:path/path.dart' as path; | ||
|
||
import 'collect_coverage.dart' as collect_coverage; | ||
|
@@ -19,37 +17,36 @@ import 'format_coverage.dart' as format_coverage; | |
final _allProcesses = <Process>[]; | ||
|
||
Future<void> _dartRun(List<String> args, | ||
{void Function(String)? onStdout, String? workingDir}) async { | ||
final process = await Process.start( | ||
Platform.executable, | ||
args, | ||
workingDirectory: workingDir, | ||
); | ||
{required void Function(String) onStdout, | ||
required void Function(String) onStderr}) async { | ||
final process = await Process.start(Platform.executable, args); | ||
_allProcesses.add(process); | ||
final broadStdout = process.stdout.asBroadcastStream(); | ||
broadStdout.listen(stdout.add); | ||
if (onStdout != null) { | ||
broadStdout.lines().listen(onStdout); | ||
|
||
void listen( | ||
Stream<List<int>> stream, IOSink sink, void Function(String) onLine) { | ||
final broadStream = stream.asBroadcastStream(); | ||
broadStream.listen(sink.add); | ||
broadStream.lines().listen(onLine); | ||
} | ||
process.stderr.listen(stderr.add); | ||
|
||
listen(process.stdout, stdout, onStdout); | ||
listen(process.stderr, stderr, onStderr); | ||
|
||
final result = await process.exitCode; | ||
if (result != 0) { | ||
throw ProcessException(Platform.executable, args, '', result); | ||
} | ||
} | ||
|
||
Future<String?> _packageNameFromConfig(String packageDir) async { | ||
final config = await findPackageConfig(Directory(packageDir)); | ||
return config?.packageOf(Uri.directory(packageDir))?.name; | ||
void _killSubprocessesAndExit(ProcessSignal signal) { | ||
for (final process in _allProcesses) { | ||
process.kill(signal); | ||
} | ||
exit(1); | ||
} | ||
|
||
void _watchExitSignal(ProcessSignal signal) { | ||
signal.watch().listen((sig) { | ||
for (final process in _allProcesses) { | ||
process.kill(sig); | ||
} | ||
exit(1); | ||
}); | ||
signal.watch().listen(_killSubprocessesAndExit); | ||
} | ||
|
||
ArgParser _createArgParser(CoverageOptions defaultOptions) => ArgParser() | ||
|
@@ -61,10 +58,10 @@ ArgParser _createArgParser(CoverageOptions defaultOptions) => ArgParser() | |
..addOption( | ||
'package-name', | ||
help: 'Name of the package to test. ' | ||
'Deduced from --package if not provided.', | ||
defaultsTo: defaultOptions.packageName, | ||
'Deduced from --package if not provided. ' | ||
'DEPRECATED: use --scope-output', | ||
) | ||
..addOption('port', help: 'VM service port.', defaultsTo: '8181') | ||
..addOption('port', help: 'VM service port. Defaults to using any free port.') | ||
..addOption( | ||
'out', | ||
defaultsTo: defaultOptions.outputDirectory, | ||
|
@@ -93,13 +90,13 @@ ArgParser _createArgParser(CoverageOptions defaultOptions) => ArgParser() | |
defaultsTo: defaultOptions.scopeOutput, | ||
help: 'restrict coverage results so that only scripts that start with ' | ||
'the provided package path are considered. Defaults to the name of ' | ||
'the package under test.') | ||
'the current package (including all subpackages, if this is a ' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm assuming one can still specify which subpackages one want coverage for with E.g.
If I use The test projects are usually part of the workspace w.r.t. analysis. However, they are not part of the packages we want code coverage stats for. (I know it's not what this PR is doing, because it's automating the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The scoping is based on the package URI:
|
||
'workspace).') | ||
..addFlag('help', abbr: 'h', negatable: false, help: 'Show this help.'); | ||
|
||
class Flags { | ||
Flags( | ||
this.packageDir, | ||
this.packageName, | ||
this.outDir, | ||
this.port, | ||
this.testScript, | ||
|
@@ -111,7 +108,6 @@ class Flags { | |
}); | ||
|
||
final String packageDir; | ||
final String packageName; | ||
final String outDir; | ||
final String port; | ||
final String testScript; | ||
|
@@ -157,25 +153,23 @@ ${parser.usage} | |
fail('--package is not a valid directory.'); | ||
} | ||
|
||
final packageName = (args['package-name'] as String?) ?? | ||
await _packageNameFromConfig(packageDir); | ||
if (packageName == null) { | ||
final pubspecPath = getPubspecPath(packageDir); | ||
if (!File(pubspecPath).existsSync()) { | ||
fail( | ||
"Couldn't figure out package name from --package. Make sure this is a " | ||
'package directory, or try passing --package-name explicitly.', | ||
"Couldn't find $pubspecPath. Make sure this command is run in a " | ||
'package directory, or pass --package to explicitly set the directory.', | ||
); | ||
} | ||
|
||
return Flags( | ||
packageDir, | ||
packageName, | ||
(args['out'] as String?) ?? path.join(packageDir, 'coverage'), | ||
args['port'] as String, | ||
args['test'] as String, | ||
args['function-coverage'] as bool, | ||
args['branch-coverage'] as bool, | ||
args['scope-output'] as List<String>, | ||
args['fail-under'] as String?, | ||
args.option('out') ?? path.join(packageDir, 'coverage'), | ||
args.option('port') ?? '0', | ||
args.option('test')!, | ||
args.flag('function-coverage'), | ||
args.flag('branch-coverage'), | ||
args.multiOption('scope-output'), | ||
args.option('fail-under'), | ||
rest: args.rest, | ||
); | ||
} | ||
|
@@ -215,11 +209,19 @@ Future<void> main(List<String> arguments) async { | |
} | ||
} | ||
}, | ||
onStderr: (line) { | ||
if (!serviceUriCompleter.isCompleted) { | ||
if (line.contains('Could not start the VM service')) { | ||
_killSubprocessesAndExit(ProcessSignal.sigkill); | ||
} | ||
} | ||
}, | ||
); | ||
final serviceUri = await serviceUriCompleter.future; | ||
|
||
final scopes = | ||
flags.scopeOutput.isEmpty ? [flags.packageName] : flags.scopeOutput; | ||
final scopes = flags.scopeOutput.isEmpty | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This completely removes the packageName rather than deprecating it right? Better to fully remove it then if it's not supported anymore? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That would be a breaking change. |
||
? getAllWorkspaceNames(flags.packageDir) | ||
: flags.scopeOutput; | ||
await collect_coverage.main([ | ||
'--wait-paused', | ||
'--resume-isolates', | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
tags: | ||
# Tests that start subprocesses, so are slower and can be a bit flaky. | ||
integration: | ||
timeout: 2x | ||
retry: 3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any possibility that a user will be assuming that 8181 is being used by default? If the VM service from the spawned process is something we expect users to want to connect to, this is a breaking change in behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I considered that, but it seems pretty unlikely. I'd expect people to be manually specifying the port if they need that sort of thing.