Outdated overrides (#2423)
* Handle overrides
* Revert debugging print
* More debugging prints
* Remove unused import
* Added --no-dependency-overrides
* Updated test golden
* Handling failing resolutions
* Log message when resolution fails
* Better json output
Co-authored-by: Sigurd Meldgaard <sigurdm@google.com>
diff --git a/lib/src/command/outdated.dart b/lib/src/command/outdated.dart
index 3ab8795..afa44b6 100644
--- a/lib/src/command/outdated.dart
+++ b/lib/src/command/outdated.dart
@@ -17,7 +17,6 @@
import '../package_name.dart';
import '../pubspec.dart';
import '../solver.dart';
-import '../source.dart';
import '../source/hosted.dart';
class OutdatedCommand extends PubCommand {
@@ -54,6 +53,12 @@
help: 'When true take dev-dependencies into account when resolving.',
);
+ argParser.addFlag(
+ 'dependency-overrides',
+ defaultsTo: true,
+ help: 'Show resolutions with `dependency_override`',
+ );
+
argParser.addOption('mark',
help: 'Highlight packages with some property in the report.',
valueHelp: 'OPTION',
@@ -67,37 +72,30 @@
entrypoint.assertUpToDate();
final includeDevDependencies = argResults['dev-dependencies'];
+ final includeDependencyOverrides = argResults['dependency-overrides'];
- final upgradePubspec = includeDevDependencies
+ final rootPubspec = includeDependencyOverrides
? entrypoint.root.pubspec
- : _stripDevDependencies(entrypoint.root.pubspec);
+ : _stripDependencyOverrides(entrypoint.root.pubspec);
- var resolvablePubspec = _stripVersionConstraints(upgradePubspec);
+ final upgradablePubspec = includeDevDependencies
+ ? rootPubspec
+ : _stripDevDependencies(rootPubspec);
+
+ final resolvablePubspec = _stripVersionConstraints(upgradablePubspec);
List<PackageId> upgradablePackages;
List<PackageId> resolvablePackages;
- Future<void> resolve() async {
- upgradablePackages = (await resolveVersions(
- SolveType.UPGRADE,
- cache,
- Package.inMemory(upgradePubspec),
- ))
- .packages;
-
- resolvablePackages = (await resolveVersions(
- SolveType.UPGRADE,
- cache,
- Package.inMemory(resolvablePubspec),
- ))
- .packages;
- }
-
final shouldShowSpinner = stdout.hasTerminal && !argResults['json'];
if (shouldShowSpinner) {
- await log.spinner('Resolving', resolve);
+ await log.spinner('Resolving', () async {
+ upgradablePackages = await _tryResolve(upgradablePubspec);
+ resolvablePackages = await _tryResolve(resolvablePubspec);
+ });
} else {
- await resolve();
+ upgradablePackages = await _tryResolve(upgradablePubspec);
+ resolvablePackages = await _tryResolve(resolvablePubspec);
}
final currentPackages = entrypoint.lockFile.packages.values;
@@ -106,62 +104,87 @@
/// closure of the non-dev dependencies from the root in at least one of
/// the current, upgradable and resolvable resolutions.
final nonDevDependencies = <String>{
- ...await nonDevDependencyClosure(entrypoint.root, currentPackages),
- ...await nonDevDependencyClosure(entrypoint.root, upgradablePackages),
- ...await nonDevDependencyClosure(entrypoint.root, resolvablePackages)
+ ...await _nonDevDependencyClosure(entrypoint.root, currentPackages),
+ ...await _nonDevDependencyClosure(entrypoint.root, upgradablePackages),
+ ...await _nonDevDependencyClosure(entrypoint.root, resolvablePackages),
};
Future<_PackageDetails> analyzeDependency(PackageRef packageRef) async {
final name = packageRef.name;
- final current = (entrypoint.lockFile?.packages ?? {})[name]?.version;
- final source = packageRef.source;
- final available = (await cache.source(source).doGetVersions(packageRef))
- .map((id) => id.version)
- .toList()
- ..sort(argResults['pre-releases'] ? null : Version.prioritize);
- final upgradable = upgradablePackages
- .firstWhere((id) => id.name == name, orElse: () => null)
- ?.version;
- final resolvable = resolvablePackages
- .firstWhere((id) => id.name == name, orElse: () => null)
- ?.version;
- final latest = available.last;
- final description = packageRef.description;
+ final current = (entrypoint.lockFile?.packages ?? {})[name];
+
+ final upgradable = upgradablePackages.firstWhere((id) => id.name == name,
+ orElse: () => null);
+ final resolvable = resolvablePackages.firstWhere((id) => id.name == name,
+ orElse: () => null);
+
+ // Find the latest version, and if it's overridden.
+ var latestIsOverridden = false;
+ PackageId latest;
+ // If not overridden in current resolution we can use this
+ if (!entrypoint.root.pubspec.dependencyOverrides.containsKey(name)) {
+ latest ??= await _getLatest(current);
+ }
+ // If present as a dependency or dev_dependency we use this
+ latest ??= await _getLatest(rootPubspec.dependencies[name]);
+ latest ??= await _getLatest(rootPubspec.devDependencies[name]);
+ // If not overridden and present in either upgradable or resolvable we
+ // use this reference to find the latest
+ if (!upgradablePubspec.dependencyOverrides.containsKey(name)) {
+ latest ??= await _getLatest(upgradable);
+ }
+ if (!resolvablePubspec.dependencyOverrides.containsKey(name)) {
+ latest ??= await _getLatest(resolvable);
+ }
+ // Otherwise, we might simply not have a latest, when a transitive
+ // dependency is overridden the source can depend on which versions we
+ // are picking. This is not a problem on `pub.dev` because it does not
+ // allow 3rd party pub servers, but other servers might. Hence, we choose
+ // to fallback to using the overridden source for latest.
+ if (latest == null) {
+ latest ??= await _getLatest(current ?? upgradable ?? resolvable);
+ latestIsOverridden = true;
+ }
+
return _PackageDetails(
- name,
- await _describeVersion(name, source, description, current),
- await _describeVersion(name, source, description, upgradable),
- await _describeVersion(name, source, description, resolvable),
- await _describeVersion(name, source, description, latest),
- _kind(name, entrypoint, nonDevDependencies));
+ name,
+ await _describeVersion(
+ current,
+ entrypoint.root.pubspec.dependencyOverrides.containsKey(name),
+ ),
+ await _describeVersion(
+ upgradable,
+ upgradablePubspec.dependencyOverrides.containsKey(name),
+ ),
+ await _describeVersion(
+ resolvable,
+ resolvablePubspec.dependencyOverrides.containsKey(name),
+ ),
+ await _describeVersion(
+ latest,
+ latestIsOverridden,
+ ),
+ _kind(name, entrypoint, nonDevDependencies),
+ );
}
final rows = <_PackageDetails>[];
- final immediateDependencies = entrypoint.root.immediateDependencies.values;
-
- for (final packageRange in immediateDependencies) {
- rows.add(await analyzeDependency(packageRange.toRef()));
- }
-
- // Now add transitive dependencies:
final visited = <String>{
entrypoint.root.name,
- ...immediateDependencies.map((d) => d.name)
};
+ // Add all dependencies from the lockfile.
for (final id in [
...currentPackages,
...upgradablePackages,
...resolvablePackages
]) {
- final name = id.name;
- if (!visited.add(name)) continue;
+ if (!visited.add(id.name)) continue;
rows.add(await analyzeDependency(id.toRef()));
}
if (!argResults['up-to-date']) {
- rows.retainWhere(
- (r) => (r.current ?? r.upgradable)?.version != r.latest?.version);
+ rows.retainWhere((r) => (r.current ?? r.upgradable) != r.latest);
}
if (!includeDevDependencies) {
rows.removeWhere((r) => r.kind == _DependencyKind.dev);
@@ -187,32 +210,88 @@
}
}
+ /// Get the latest version of [package].
+ ///
+ /// Returns `null`, if unable to find the package.
+ Future<PackageId> _getLatest(PackageName package) async {
+ if (package == null) {
+ return null;
+ }
+ final ref = package.toRef();
+ final available = await cache.source(ref.source).getVersions(ref);
+ if (available.isEmpty) {
+ return null;
+ }
+ available.sort(argResults['pre-releases']
+ ? (x, y) => x.version.compareTo(y.version)
+ : (x, y) => Version.prioritize(x.version, y.version));
+ return available.last;
+ }
+
/// Retrieves the pubspec of package [name] in [version] from [source].
- Future<Pubspec> _describeVersion(
- String name, Source source, dynamic description, Version version) async {
- return version == null
- ? null
- : await cache
- .source(source)
- .describe(PackageId(name, source, version, description));
+ ///
+ /// Returns `null`, if given `null` as a convinience.
+ Future<_VersionDetails> _describeVersion(
+ PackageId id,
+ bool isOverridden,
+ ) async {
+ if (id == null) {
+ return null;
+ }
+ return _VersionDetails(
+ await cache.source(id.source).describe(id),
+ id,
+ isOverridden,
+ );
}
/// Computes the closure of the graph of dependencies (not including
- /// dev_dependencies from [root], given the package versions in [resolution].
- Future<Set<String>> nonDevDependencyClosure(
- Package root, Iterable<PackageId> resolution) async {
- final mapping =
- Map<String, PackageId>.fromIterable(resolution, key: (id) => id.name);
- final visited = <String>{root.name};
- final toVisit = [...root.dependencies.keys];
- while (toVisit.isNotEmpty) {
- final name = toVisit.removeLast();
- if (!visited.add(name)) continue;
- final id = mapping[name];
- toVisit.addAll(
- (await cache.source(id.source).describe(id)).dependencies.keys);
+ /// `dev_dependencies` from [root], given the package versions
+ /// in [resolution].
+ ///
+ /// The [resolution] is allowed to be a partial (or empty) resolution not
+ /// satisfying all the dependencies of [root].
+ Future<Set<String>> _nonDevDependencyClosure(
+ Package root,
+ Iterable<PackageId> resolution,
+ ) async {
+ final nameToId = Map<String, PackageId>.fromIterable(
+ resolution,
+ key: (id) => id.name,
+ );
+
+ final nonDevDependencies = <String>{root.name};
+ final queue = [...root.dependencies.keys];
+
+ while (queue.isNotEmpty) {
+ final name = queue.removeLast();
+ if (!nonDevDependencies.add(name)) {
+ continue;
+ }
+
+ final id = nameToId[name];
+ if (id == null) {
+ continue; // allow partial resolutions
+ }
+ final pubspec = await cache.source(id.source).describe(id);
+ queue.addAll(pubspec.dependencies.keys);
}
- return visited;
+
+ return nonDevDependencies;
+ }
+
+ /// Try to solve [pubspec] return [PackageId]'s in the resolution or `null`.
+ Future<List<PackageId>> _tryResolve(Pubspec pubspec) async {
+ try {
+ return (await resolveVersions(
+ SolveType.UPGRADE,
+ cache,
+ Package.inMemory(pubspec),
+ ))
+ .packages;
+ } on SolveFailure {
+ return [];
+ }
}
}
@@ -223,7 +302,18 @@
sdkConstraints: original.sdkConstraints,
dependencies: original.dependencies.values,
devDependencies: [], // explicitly give empty list, to prevent lazy parsing
- // TODO(sigurdm): consider dependency overrides.
+ dependencyOverrides: original.dependencyOverrides.values,
+ );
+}
+
+Pubspec _stripDependencyOverrides(Pubspec original) {
+ return Pubspec(
+ original.name,
+ version: original.version,
+ sdkConstraints: original.sdkConstraints,
+ dependencies: original.dependencies.values,
+ devDependencies: original.devDependencies.values,
+ dependencyOverrides: [],
);
}
@@ -254,7 +344,7 @@
sdkConstraints: original.sdkConstraints,
dependencies: _unconstrained(original.dependencies),
devDependencies: _unconstrained(original.devDependencies),
- // TODO(sigurdm): consider dependency overrides.
+ dependencyOverrides: original.dependencyOverrides.values,
);
}
@@ -263,9 +353,12 @@
.convert({'packages': rows.map((row) => row.toJson()).toList()}));
}
-Future<void> _outputHuman(List<_PackageDetails> rows,
- Future<List<_FormattedString>> Function(_PackageDetails) marker,
- {@required bool useColors, @required bool includeDevDependencies}) async {
+Future<void> _outputHuman(
+ List<_PackageDetails> rows,
+ Future<List<_FormattedString>> Function(_PackageDetails) marker, {
+ @required bool useColors,
+ @required bool includeDevDependencies,
+}) async {
if (rows.isEmpty) {
log.message('Found no outdated packages.');
return;
@@ -343,7 +436,7 @@
if (upgradable != 0) {
if (upgradable == 1) {
- log.message('1 upgradable dependency is locked (in pubspec.lock) to '
+ log.message('\n1 upgradable dependency is locked (in pubspec.lock) to '
'an older version.\n'
'To update it, use `pub upgrade`.');
} else {
@@ -375,28 +468,27 @@
Future<List<_FormattedString>> oudatedMarker(
_PackageDetails packageDetails) async {
final cols = [_FormattedString(packageDetails.name)];
- Version previous;
- for (final pubspec in [
+ _VersionDetails previous;
+ for (final versionDetails in [
packageDetails.current,
packageDetails.upgradable,
packageDetails.resolvable,
packageDetails.latest
]) {
- final version = pubspec?.version;
- if (version == null) {
+ if (versionDetails == null) {
cols.add(_raw('-'));
} else {
- final isLatest = version == packageDetails.latest.version;
+ final isLatest = versionDetails == packageDetails.latest;
String Function(String) color;
if (isLatest) {
- color = version == previous ? color = log.gray : null;
+ color = versionDetails == previous ? color = log.gray : null;
} else {
color = log.red;
}
final prefix = isLatest ? '' : '*';
- cols.add(_format(version?.toString() ?? '-', color, prefix: prefix));
+ cols.add(_format(versionDetails.describe ?? '-', color, prefix: prefix));
}
- previous = version;
+ previous = versionDetails;
}
return cols;
}
@@ -410,16 +502,46 @@
packageDetails.upgradable,
packageDetails.resolvable,
packageDetails.latest,
- ].map((p) => _raw(p?.version?.toString() ?? '-'))
+ ].map((p) => _raw(p?.describe ?? '-'))
];
}
+/// Details about a single version of a package.
+class _VersionDetails {
+ final Pubspec _pubspec;
+
+ /// True if this version is overridden.
+ final bool _overridden;
+ final PackageId _id;
+ _VersionDetails(this._pubspec, this._id, this._overridden);
+
+ /// A string representation of this version to include in the outdated report.
+ String get describe {
+ final version = _pubspec.version;
+ final suffix = _overridden ? ' (overridden)' : '';
+ return '$version$suffix';
+ }
+
+ Map<String, Object> toJson() => {
+ 'version': _pubspec.version.toString(),
+ if (_overridden) 'overridden': true,
+ };
+
+ @override
+ bool operator ==(Object other) =>
+ identical(this, other) ||
+ other is _VersionDetails &&
+ _overridden == other._overridden &&
+ _id.source == other._id.source &&
+ _pubspec.version == other._pubspec.version;
+}
+
class _PackageDetails implements Comparable<_PackageDetails> {
final String name;
- final Pubspec current;
- final Pubspec upgradable;
- final Pubspec resolvable;
- final Pubspec latest;
+ final _VersionDetails current;
+ final _VersionDetails upgradable;
+ final _VersionDetails resolvable;
+ final _VersionDetails latest;
final _DependencyKind kind;
_PackageDetails(this.name, this.current, this.upgradable, this.resolvable,
@@ -436,10 +558,10 @@
Map<String, Object> toJson() {
return {
'package': name,
- 'current': {'version': current?.version?.toString()},
- 'upgradable': {'version': upgradable?.version?.toString()},
- 'resolvable': {'version': resolvable?.version?.toString()},
- 'latest': {'version': latest?.version?.toString()},
+ 'current': current?.toJson(),
+ 'upgradable': upgradable?.toJson(),
+ 'resolvable': resolvable?.toJson(),
+ 'latest': latest?.toJson(),
};
}
}
diff --git a/test/outdated/goldens/circular_dependencies.txt b/test/outdated/goldens/circular_dependencies.txt
index 1571b06..3e4bd80 100644
--- a/test/outdated/goldens/circular_dependencies.txt
+++ b/test/outdated/goldens/circular_dependencies.txt
@@ -28,6 +28,7 @@
transitive dependencies: all up-to-date
transitive dev_dependencies: all up-to-date
+
1 upgradable dependency is locked (in pubspec.lock) to an older version.
To update it, use `pub upgrade`.
@@ -40,6 +41,7 @@
transitive dependencies: all up-to-date
transitive dev_dependencies: all up-to-date
+
1 upgradable dependency is locked (in pubspec.lock) to an older version.
To update it, use `pub upgrade`.
@@ -52,6 +54,7 @@
transitive dependencies: all up-to-date
transitive dev_dependencies: all up-to-date
+
1 upgradable dependency is locked (in pubspec.lock) to an older version.
To update it, use `pub upgrade`.
@@ -64,6 +67,7 @@
transitive dependencies: all up-to-date
transitive dev_dependencies: all up-to-date
+
1 upgradable dependency is locked (in pubspec.lock) to an older version.
To update it, use `pub upgrade`.
@@ -72,6 +76,20 @@
foo *1.2.3 1.3.0 1.3.0 1.3.0
transitive dependencies: all up-to-date
+
+1 upgradable dependency is locked (in pubspec.lock) to an older version.
+To update it, use `pub upgrade`.
+
+$ pub outdated --no-color --no-dependency-overrides
+Dependencies Current Upgradable Resolvable Latest
+foo *1.2.3 1.3.0 1.3.0 1.3.0
+
+dev_dependencies: all up-to-date
+
+transitive dependencies: all up-to-date
+
+transitive dev_dependencies: all up-to-date
+
1 upgradable dependency is locked (in pubspec.lock) to an older version.
To update it, use `pub upgrade`.
diff --git a/test/outdated/goldens/dependency_overrides.txt b/test/outdated/goldens/dependency_overrides.txt
new file mode 100644
index 0000000..95e1a57
--- /dev/null
+++ b/test/outdated/goldens/dependency_overrides.txt
@@ -0,0 +1,149 @@
+$ pub outdated --json
+{
+ "packages": [
+ {
+ "package": "bar",
+ "current": {
+ "version": "1.0.1",
+ "overridden": true
+ },
+ "upgradable": {
+ "version": "1.0.1",
+ "overridden": true
+ },
+ "resolvable": {
+ "version": "1.0.1",
+ "overridden": true
+ },
+ "latest": {
+ "version": "2.0.0"
+ }
+ },
+ {
+ "package": "baz",
+ "current": {
+ "version": "2.0.0",
+ "overridden": true
+ },
+ "upgradable": {
+ "version": "2.0.0",
+ "overridden": true
+ },
+ "resolvable": {
+ "version": "2.0.0",
+ "overridden": true
+ },
+ "latest": {
+ "version": "2.0.0"
+ }
+ },
+ {
+ "package": "foo",
+ "current": {
+ "version": "1.0.1",
+ "overridden": true
+ },
+ "upgradable": {
+ "version": "1.0.1",
+ "overridden": true
+ },
+ "resolvable": {
+ "version": "1.0.1",
+ "overridden": true
+ },
+ "latest": {
+ "version": "2.0.0"
+ }
+ }
+ ]
+}
+
+$ pub outdated --no-color
+Dependencies Current Upgradable Resolvable Latest
+bar *1.0.1 (overridden) *1.0.1 (overridden) *1.0.1 (overridden) 2.0.0
+baz *2.0.0 (overridden) *2.0.0 (overridden) *2.0.0 (overridden) 2.0.0
+foo *1.0.1 (overridden) *1.0.1 (overridden) *1.0.1 (overridden) 2.0.0
+
+dev_dependencies: all up-to-date
+
+transitive dependencies: all up-to-date
+
+transitive dev_dependencies: all up-to-date
+
+Dependencies are all on the latest resolvable versions.
+Newer versions, while available, are not mutually compatible.
+
+$ pub outdated --no-color --mark=none
+Dependencies Current Upgradable Resolvable Latest
+bar 1.0.1 (overridden) 1.0.1 (overridden) 1.0.1 (overridden) 2.0.0
+baz 2.0.0 (overridden) 2.0.0 (overridden) 2.0.0 (overridden) 2.0.0
+foo 1.0.1 (overridden) 1.0.1 (overridden) 1.0.1 (overridden) 2.0.0
+
+dev_dependencies: all up-to-date
+
+transitive dependencies: all up-to-date
+
+transitive dev_dependencies: all up-to-date
+
+Dependencies are all on the latest resolvable versions.
+Newer versions, while available, are not mutually compatible.
+
+$ pub outdated --no-color --up-to-date
+Dependencies Current Upgradable Resolvable Latest
+bar *1.0.1 (overridden) *1.0.1 (overridden) *1.0.1 (overridden) 2.0.0
+baz *2.0.0 (overridden) *2.0.0 (overridden) *2.0.0 (overridden) 2.0.0
+foo *1.0.1 (overridden) *1.0.1 (overridden) *1.0.1 (overridden) 2.0.0
+
+dev_dependencies: all up-to-date
+
+transitive dependencies: all up-to-date
+
+transitive dev_dependencies: all up-to-date
+
+Dependencies are all on the latest resolvable versions.
+Newer versions, while available, are not mutually compatible.
+
+$ pub outdated --no-color --pre-releases
+Dependencies Current Upgradable Resolvable Latest
+bar *1.0.1 (overridden) *1.0.1 (overridden) *1.0.1 (overridden) 2.0.0
+baz *2.0.0 (overridden) *2.0.0 (overridden) *2.0.0 (overridden) 2.0.0
+foo *1.0.1 (overridden) *1.0.1 (overridden) *1.0.1 (overridden) 2.0.0
+
+dev_dependencies: all up-to-date
+
+transitive dependencies: all up-to-date
+
+transitive dev_dependencies: all up-to-date
+
+Dependencies are all on the latest resolvable versions.
+Newer versions, while available, are not mutually compatible.
+
+$ pub outdated --no-color --no-dev-dependencies
+Dependencies Current Upgradable Resolvable Latest
+bar *1.0.1 (overridden) *1.0.1 (overridden) *1.0.1 (overridden) 2.0.0
+baz *2.0.0 (overridden) *2.0.0 (overridden) *2.0.0 (overridden) 2.0.0
+foo *1.0.1 (overridden) *1.0.1 (overridden) *1.0.1 (overridden) 2.0.0
+
+transitive dependencies: all up-to-date
+
+Dependencies are all on the latest resolvable versions.
+Newer versions, while available, are not mutually compatible.
+
+$ pub outdated --no-color --no-dependency-overrides
+Dependencies Current Upgradable Resolvable Latest
+bar *1.0.1 (overridden) 2.0.0 2.0.0 2.0.0
+baz *2.0.0 (overridden) *1.0.0 2.0.0 2.0.0
+foo *1.0.1 (overridden) *1.0.0 *1.0.0 2.0.0
+
+dev_dependencies: all up-to-date
+
+transitive dependencies: all up-to-date
+
+transitive dev_dependencies: all up-to-date
+
+3 upgradable dependencies are locked (in pubspec.lock) to older versions.
+To update these dependencies, use `pub upgrade`.
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml.
+
diff --git a/test/outdated/goldens/dependency_overrides_no_solution.txt b/test/outdated/goldens/dependency_overrides_no_solution.txt
new file mode 100644
index 0000000..dbf27fb
--- /dev/null
+++ b/test/outdated/goldens/dependency_overrides_no_solution.txt
@@ -0,0 +1,122 @@
+$ pub outdated --json
+{
+ "packages": [
+ {
+ "package": "bar",
+ "current": {
+ "version": "1.0.0",
+ "overridden": true
+ },
+ "upgradable": {
+ "version": "1.0.0",
+ "overridden": true
+ },
+ "resolvable": {
+ "version": "1.0.0",
+ "overridden": true
+ },
+ "latest": {
+ "version": "2.0.0"
+ }
+ },
+ {
+ "package": "foo",
+ "current": {
+ "version": "1.0.0",
+ "overridden": true
+ },
+ "upgradable": {
+ "version": "1.0.0",
+ "overridden": true
+ },
+ "resolvable": {
+ "version": "1.0.0",
+ "overridden": true
+ },
+ "latest": {
+ "version": "2.0.0"
+ }
+ }
+ ]
+}
+
+$ pub outdated --no-color
+Dependencies Current Upgradable Resolvable Latest
+bar *1.0.0 (overridden) *1.0.0 (overridden) *1.0.0 (overridden) 2.0.0
+foo *1.0.0 (overridden) *1.0.0 (overridden) *1.0.0 (overridden) 2.0.0
+
+dev_dependencies: all up-to-date
+
+transitive dependencies: all up-to-date
+
+transitive dev_dependencies: all up-to-date
+
+Dependencies are all on the latest resolvable versions.
+Newer versions, while available, are not mutually compatible.
+
+$ pub outdated --no-color --mark=none
+Dependencies Current Upgradable Resolvable Latest
+bar 1.0.0 (overridden) 1.0.0 (overridden) 1.0.0 (overridden) 2.0.0
+foo 1.0.0 (overridden) 1.0.0 (overridden) 1.0.0 (overridden) 2.0.0
+
+dev_dependencies: all up-to-date
+
+transitive dependencies: all up-to-date
+
+transitive dev_dependencies: all up-to-date
+
+Dependencies are all on the latest resolvable versions.
+Newer versions, while available, are not mutually compatible.
+
+$ pub outdated --no-color --up-to-date
+Dependencies Current Upgradable Resolvable Latest
+bar *1.0.0 (overridden) *1.0.0 (overridden) *1.0.0 (overridden) 2.0.0
+foo *1.0.0 (overridden) *1.0.0 (overridden) *1.0.0 (overridden) 2.0.0
+
+dev_dependencies: all up-to-date
+
+transitive dependencies: all up-to-date
+
+transitive dev_dependencies: all up-to-date
+
+Dependencies are all on the latest resolvable versions.
+Newer versions, while available, are not mutually compatible.
+
+$ pub outdated --no-color --pre-releases
+Dependencies Current Upgradable Resolvable Latest
+bar *1.0.0 (overridden) *1.0.0 (overridden) *1.0.0 (overridden) 2.0.0
+foo *1.0.0 (overridden) *1.0.0 (overridden) *1.0.0 (overridden) 2.0.0
+
+dev_dependencies: all up-to-date
+
+transitive dependencies: all up-to-date
+
+transitive dev_dependencies: all up-to-date
+
+Dependencies are all on the latest resolvable versions.
+Newer versions, while available, are not mutually compatible.
+
+$ pub outdated --no-color --no-dev-dependencies
+Dependencies Current Upgradable Resolvable Latest
+bar *1.0.0 (overridden) *1.0.0 (overridden) *1.0.0 (overridden) 2.0.0
+foo *1.0.0 (overridden) *1.0.0 (overridden) *1.0.0 (overridden) 2.0.0
+
+transitive dependencies: all up-to-date
+
+Dependencies are all on the latest resolvable versions.
+Newer versions, while available, are not mutually compatible.
+
+$ pub outdated --no-color --no-dependency-overrides
+Dependencies Current Upgradable Resolvable Latest
+bar *1.0.0 (overridden) - - 2.0.0
+foo *1.0.0 (overridden) - - 2.0.0
+
+dev_dependencies: all up-to-date
+
+transitive dependencies: all up-to-date
+
+transitive dev_dependencies: all up-to-date
+
+Dependencies are all on the latest resolvable versions.
+Newer versions, while available, are not mutually compatible.
+
diff --git a/test/outdated/goldens/mutually_incompatible.txt b/test/outdated/goldens/mutually_incompatible.txt
index 1c93718..f2b8a82 100644
--- a/test/outdated/goldens/mutually_incompatible.txt
+++ b/test/outdated/goldens/mutually_incompatible.txt
@@ -100,3 +100,17 @@
Dependencies are all on the latest resolvable versions.
Newer versions, while available, are not mutually compatible.
+$ pub outdated --no-color --no-dependency-overrides
+Dependencies Current Upgradable Resolvable Latest
+bar *1.0.0 *1.0.0 *1.0.0 2.0.0
+foo *1.0.0 *1.0.0 *1.0.0 2.0.0
+
+dev_dependencies: all up-to-date
+
+transitive dependencies: all up-to-date
+
+transitive dev_dependencies: all up-to-date
+
+Dependencies are all on the latest resolvable versions.
+Newer versions, while available, are not mutually compatible.
+
diff --git a/test/outdated/goldens/newer_versions.txt b/test/outdated/goldens/newer_versions.txt
index b55af2d..8f43ef0 100644
--- a/test/outdated/goldens/newer_versions.txt
+++ b/test/outdated/goldens/newer_versions.txt
@@ -48,12 +48,8 @@
},
{
"package": "transitive2",
- "current": {
- "version": null
- },
- "upgradable": {
- "version": null
- },
+ "current": null,
+ "upgradable": null,
"resolvable": {
"version": "1.0.0"
},
@@ -63,12 +59,8 @@
},
{
"package": "transitive3",
- "current": {
- "version": null
- },
- "upgradable": {
- "version": null
- },
+ "current": null,
+ "upgradable": null,
"resolvable": {
"version": "1.0.0"
},
@@ -174,3 +166,23 @@
1 dependency is constrained to a version that is older than a resolvable version.
To update it, edit pubspec.yaml.
+$ pub outdated --no-color --no-dependency-overrides
+Dependencies Current Upgradable Resolvable Latest
+foo *1.2.3 *1.3.0 *2.0.0 3.0.0
+
+dev_dependencies
+builder *1.2.3 *1.3.0 2.0.0 2.0.0
+
+transitive dependencies
+transitive *1.2.3 *1.3.0 *1.3.0 2.0.0
+transitive2 - - 1.0.0 1.0.0
+
+transitive dev_dependencies
+transitive3 - - 1.0.0 1.0.0
+
+3 upgradable dependencies are locked (in pubspec.lock) to older versions.
+To update these dependencies, use `pub upgrade`.
+
+2 dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml.
+
diff --git a/test/outdated/goldens/no_dependencies.txt b/test/outdated/goldens/no_dependencies.txt
index c27c6d5..bfd5e07 100644
--- a/test/outdated/goldens/no_dependencies.txt
+++ b/test/outdated/goldens/no_dependencies.txt
@@ -18,3 +18,6 @@
$ pub outdated --no-color --no-dev-dependencies
Found no outdated packages.
+$ pub outdated --no-color --no-dependency-overrides
+Found no outdated packages.
+
diff --git a/test/outdated/outdated_test.dart b/test/outdated/outdated_test.dart
index 63b658e..55e9692 100644
--- a/test/outdated/outdated_test.dart
+++ b/test/outdated/outdated_test.dart
@@ -19,6 +19,7 @@
['--no-color', '--up-to-date'],
['--no-color', '--pre-releases'],
['--no-color', '--no-dev-dependencies'],
+ ['--no-color', '--no-dependency-overrides'],
]) {
final process = await startPub(args: ['outdated', ...args]);
await process.shouldExit(0);
@@ -125,4 +126,78 @@
await variations('mutually_incompatible');
});
+
+ test('overridden dependencies', () async {
+ ensureGit();
+ await servePackages(
+ (builder) => builder
+ ..serve('foo', '1.0.0')
+ ..serve('foo', '2.0.0', deps: {'bar': '^1.0.0'})
+ ..serve('bar', '1.0.0')
+ ..serve('bar', '2.0.0')
+ ..serve('baz', '1.0.0')
+ ..serve('baz', '2.0.0'),
+ );
+
+ await d.git('foo.git', [
+ d.libPubspec('foo', '1.0.1'),
+ ]).create();
+
+ await d.dir('bar', [
+ d.libPubspec('bar', '1.0.1'),
+ ]).create();
+
+ await d.dir(appPath, [
+ d.pubspec({
+ 'name': 'app',
+ 'version': '1.0.1',
+ 'dependencies': {
+ 'foo': '^1.0.0',
+ 'bar': '^2.0.0',
+ 'baz': '^1.0.0',
+ },
+ 'dependency_overrides': {
+ 'foo': {
+ 'git': {'url': '../foo.git'}
+ },
+ 'bar': {'path': '../bar'},
+ 'baz': '2.0.0'
+ },
+ })
+ ]).create();
+
+ await pubGet();
+
+ await variations('dependency_overrides');
+ });
+
+ test('overridden dependencies - no resolution', () async {
+ ensureGit();
+ await servePackages(
+ (builder) => builder
+ ..serve('foo', '1.0.0', deps: {'bar': '^2.0.0'})
+ ..serve('foo', '2.0.0', deps: {'bar': '^1.0.0'})
+ ..serve('bar', '1.0.0', deps: {'foo': '^1.0.0'})
+ ..serve('bar', '2.0.0', deps: {'foo': '^2.0.0'}),
+ );
+
+ await d.dir(appPath, [
+ d.pubspec({
+ 'name': 'app',
+ 'version': '1.0.1',
+ 'dependencies': {
+ 'foo': 'any',
+ 'bar': 'any',
+ },
+ 'dependency_overrides': {
+ 'foo': '1.0.0',
+ 'bar': '1.0.0',
+ },
+ })
+ ]).create();
+
+ await pubGet();
+
+ await variations('dependency_overrides_no_solution');
+ });
}