Support --version in pub workspace (#2538)
Closes #2535
Add a check for the `workspace_ref.json` file in place of the
`pubspec.lock` file that exists for single package pub solutions.
When the workspace ref exists, follow it and read the
`package_graph.json` file from the workspace root.
diff --git a/pkgs/test/test/runner/json_reporter_utils.dart b/pkgs/test/test/runner/json_reporter_utils.dart
index 7416c0a..eec2808 100644
--- a/pkgs/test/test/runner/json_reporter_utils.dart
+++ b/pkgs/test/test/runner/json_reporter_utils.dart
@@ -6,7 +6,6 @@
import 'package:path/path.dart' as p;
import 'package:test/test.dart';
-import 'package:test_core/src/runner/version.dart';
import 'package:test_descriptor/test_descriptor.dart' as d;
/// Asserts that the outputs from running tests with a JSON reporter match the
@@ -41,7 +40,8 @@
final start = {
'type': 'start',
'protocolVersion': '0.1.1',
- 'runnerVersion': testVersion,
+ // Runner version cannot be read in the synthetic package
+ 'runnerVersion': null,
'pid': testPid,
};
expect(decoded.first, equals(start));
diff --git a/pkgs/test_core/CHANGELOG.md b/pkgs/test_core/CHANGELOG.md
index 885647d..27324b6 100644
--- a/pkgs/test_core/CHANGELOG.md
+++ b/pkgs/test_core/CHANGELOG.md
@@ -7,6 +7,7 @@
* Suppress skip reason messages in the compact and failures-only reporters.
* Fix default coverage filter when running in a workspace package. Default
filter now includes all the workspace's package.
+* Add support for reading test package version within pub workspaces.
## 0.6.14
diff --git a/pkgs/test_core/lib/src/runner/version.dart b/pkgs/test_core/lib/src/runner/version.dart
index aff6791..05054ce 100644
--- a/pkgs/test_core/lib/src/runner/version.dart
+++ b/pkgs/test_core/lib/src/runner/version.dart
@@ -2,60 +2,92 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'dart:convert';
import 'dart:io';
+import 'package:collection/collection.dart';
+import 'package:path/path.dart' as p;
import 'package:yaml/yaml.dart';
/// The version number of the test runner, or `null` if it couldn't be loaded.
///
/// This is a semantic version, optionally followed by a space and additional
/// data about its source.
-final String? testVersion =
- (() {
- dynamic lockfile;
- try {
- lockfile = loadYaml(File('pubspec.lock').readAsStringSync());
- } on FormatException catch (_) {
- return null;
- } on IOException catch (_) {
- return null;
- }
+final String? testVersion = _readWorkspaceRef() ?? _readPubspecLock();
- if (lockfile is! Map) return null;
- var packages = lockfile['packages'];
- if (packages is! Map) return null;
- var package = packages['test'];
- if (package is! Map) return null;
+String? _readWorkspaceRef() {
+ try {
+ final pubDirectory = p.join('.dart_tool', 'pub');
+ final workspaceRefFile = File(p.join(pubDirectory, 'workspace_ref.json'));
+ if (!workspaceRefFile.existsSync()) return null;
+ final workspaceRef = jsonDecode(workspaceRefFile.readAsStringSync());
+ if (workspaceRef is! Map) return null;
+ final relativeRoot = workspaceRef['workspaceRoot'];
+ if (relativeRoot is! String) return null;
+ final packageGraphPath = p.normalize(
+ p.join(pubDirectory, relativeRoot, '.dart_tool', 'package_graph.json'),
+ );
+ final packageGraph = jsonDecode(File(packageGraphPath).readAsStringSync());
+ if (packageGraph is! Map) return null;
+ final packages = packageGraph['packages'];
+ if (packages is! List) return null;
+ final testPackage = packages.firstWhereOrNull(
+ (p) => p is Map && p['name'] == 'test',
+ );
+ if (testPackage == null) return null;
+ return (testPackage as Map)['version'] as String;
+ } on FormatException {
+ return null;
+ } on IOException {
+ return null;
+ }
+}
- var source = package['source'];
- if (source is! String) return null;
+String? _readPubspecLock() {
+ dynamic lockfile;
+ try {
+ lockfile = loadYaml(File('pubspec.lock').readAsStringSync());
+ } on FormatException {
+ return null;
+ } on IOException {
+ return null;
+ }
- switch (source) {
- case 'hosted':
- var version = package['version'];
- return (version is String) ? version : null;
+ if (lockfile is! Map) return null;
+ var packages = lockfile['packages'];
+ if (packages is! Map) return null;
+ var package = packages['test'];
+ if (package is! Map) return null;
- case 'git':
- var version = package['version'];
- if (version is! String) return null;
- var description = package['description'];
- if (description is! Map) return null;
- var ref = description['resolved-ref'];
- if (ref is! String) return null;
+ var source = package['source'];
+ if (source is! String) return null;
- return '$version (${ref.substring(0, 7)})';
+ switch (source) {
+ case 'hosted':
+ var version = package['version'];
+ return (version is String) ? version : null;
- case 'path':
- var version = package['version'];
- if (version is! String) return null;
- var description = package['description'];
- if (description is! Map) return null;
- var path = description['path'];
- if (path is! String) return null;
+ case 'git':
+ var version = package['version'];
+ if (version is! String) return null;
+ var description = package['description'];
+ if (description is! Map) return null;
+ var ref = description['resolved-ref'];
+ if (ref is! String) return null;
- return '$version (from $path)';
+ return '$version (${ref.substring(0, 7)})';
- default:
- return null;
- }
- })();
+ case 'path':
+ var version = package['version'];
+ if (version is! String) return null;
+ var description = package['description'];
+ if (description is! Map) return null;
+ var path = description['path'];
+ if (path is! String) return null;
+
+ return '$version (from $path)';
+
+ default:
+ return null;
+ }
+}