Skip to content
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

Add flag --unlock-transitive to pub upgrade #4403

Merged
merged 2 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 33 additions & 9 deletions lib/src/command/upgrade.dart
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ class UpgradeCommand extends PubCommand {
negatable: false,
);

argParser.addFlag(
'unlock-transitive',
help: 'Also upgrades the transitive dependencies '
'of the listed [dependencies]',
);
Comment on lines +73 to +77
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
argParser.addFlag(
'unlock-transitive',
help: 'Also upgrades the transitive dependencies '
'of the listed [dependencies]',
);
argParser.addFlag(
'unlock-transitive',
help: 'Also upgrades the transitive dependencies '
'of the listed [dependencies]',
negatable: false,
);


argParser.addFlag(
'major-versions',
help: 'Upgrades packages to their latest resolvable versions, '
Expand Down Expand Up @@ -101,11 +107,27 @@ class UpgradeCommand extends PubCommand {

bool get _precompile => argResults.flag('precompile');

late final Future<List<String>> _packagesToUpgrade =
_computePackagesToUpgrade();

/// List of package names to upgrade, if empty then upgrade all packages.
///
/// This allows the user to specify list of names that they want the
/// upgrade command to affect.
List<String> get _packagesToUpgrade => argResults.rest;
Future<List<String>> _computePackagesToUpgrade() async {
if (argResults.flag('unlock-transitive')) {
final graph = await entrypoint.packageGraph;
sigurdm marked this conversation as resolved.
Show resolved Hide resolved
return argResults.rest
.expand(
(package) =>
graph.transitiveDependencies(package).map((p) => p.name),
)
.toSet()
.toList();
} else {
return argResults.rest;
}
}

bool get _upgradeNullSafety =>
argResults.flag('nullsafety') || argResults.flag('null-safety');
Expand Down Expand Up @@ -142,7 +164,7 @@ Consider using the Dart 2.19 sdk to migrate to null safety.''');
);
}
final changes =
entrypoint.tighten(packagesToUpgrade: _packagesToUpgrade);
entrypoint.tighten(packagesToUpgrade: await _packagesToUpgrade);
entrypoint.applyChanges(changes, _dryRun);
}
}
Expand All @@ -157,7 +179,7 @@ Consider using the Dart 2.19 sdk to migrate to null safety.''');
Future<void> _runUpgrade(Entrypoint e, {bool onlySummary = false}) async {
await e.acquireDependencies(
SolveType.upgrade,
unlock: _packagesToUpgrade,
unlock: await _packagesToUpgrade,
dryRun: _dryRun,
precompile: _precompile,
summaryOnly: onlySummary,
Expand All @@ -171,7 +193,7 @@ Consider using the Dart 2.19 sdk to migrate to null safety.''');
/// given.
///
/// This assumes that `--major-versions` was passed.
List<String> _directDependenciesToUpgrade() {
Future<List<String>> _directDependenciesToUpgrade() async {
assert(_upgradeMajorVersions);

final directDeps = {
Expand All @@ -180,12 +202,13 @@ Consider using the Dart 2.19 sdk to migrate to null safety.''');
...package.devDependencies.keys,
],
}.toList();
final packagesToUpgrade = await _packagesToUpgrade;
final toUpgrade =
_packagesToUpgrade.isEmpty ? directDeps : _packagesToUpgrade;
packagesToUpgrade.isEmpty ? directDeps : packagesToUpgrade;

// Check that all package names in upgradeOnly are direct-dependencies
final notInDeps = toUpgrade.where((n) => !directDeps.contains(n));
if (toUpgrade.any(notInDeps.contains)) {
if (argResults.rest.any(notInDeps.contains)) {
usageException('''
Dependencies specified in `$topLevelProgram pub upgrade --major-versions <dependencies>` must
be direct 'dependencies' or 'dev_dependencies', following packages are not:
Expand All @@ -198,7 +221,7 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not:
}

Future<void> _runUpgradeMajorVersions() async {
final toUpgrade = _directDependenciesToUpgrade();
final toUpgrade = await _directDependenciesToUpgrade();
// Solve [resolvablePubspec] in-memory and consolidate the resolved
// versions of the packages into a map for quick searching.
final resolvedPackages = <String, PackageId>{};
Expand Down Expand Up @@ -267,7 +290,7 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not:
}),
);
changes = entrypoint.tighten(
packagesToUpgrade: _packagesToUpgrade,
packagesToUpgrade: await _packagesToUpgrade,
existingChanges: changes,
packageVersions: solveResult.packages,
);
Expand All @@ -279,7 +302,7 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not:
// But without a specific package we want to get as many non-major updates
// as possible (SolveType.upgrade).
final solveType =
_packagesToUpgrade.isEmpty ? SolveType.upgrade : SolveType.get;
(await _packagesToUpgrade).isEmpty ? SolveType.upgrade : SolveType.get;

entrypoint.applyChanges(changes, _dryRun);
await entrypoint.withUpdatedRootPubspecs({
Expand All @@ -290,6 +313,7 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not:
solveType,
dryRun: _dryRun,
precompile: !_dryRun && _precompile,
unlock: await _packagesToUpgrade,
);

// If any of the packages to upgrade are dependency overrides, then we
Expand Down
6 changes: 3 additions & 3 deletions lib/src/entrypoint.dart
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ See $workspacesDocUrl for more information.''',
/// pubspec.yaml and all dependencies downloaded.
Future<void> acquireDependencies(
SolveType type, {
Iterable<String>? unlock,
Iterable<String> unlock = const [],
bool dryRun = false,
bool precompile = false,
bool summaryOnly = false,
Expand Down Expand Up @@ -547,7 +547,7 @@ Try running `$topLevelProgram pub get` to create `$lockFilePath`.''');
cache,
workspaceRoot,
lockFile: lockFile,
unlock: unlock ?? [],
unlock: unlock,
);
});
} on SolveFailure catch (e) {
Expand All @@ -557,7 +557,7 @@ Try running `$topLevelProgram pub get` to create `$lockFilePath`.''');
this,
type,
e.incompatibility,
unlock ?? [],
unlock,
cache,
),
);
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ dependencies:
tar: ^2.0.0
typed_data: ^1.3.2
yaml: ^3.1.2
yaml_edit: ^2.1.1
yaml_edit: ^2.2.1

dev_dependencies:
checks: ^0.3.0
Expand Down
1 change: 1 addition & 0 deletions test/testdata/goldens/help_test/pub upgrade --help.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Usage: pub upgrade [dependencies...]
-n, --dry-run Report what dependencies would change but don't change any.
--[no-]precompile Precompile executables in immediate dependencies.
--tighten Updates lower bounds in pubspec.yaml to match the resolved version.
--[no-]transitive Also upgrades the transitive dependencies of the listed [dependencies]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
--[no-]transitive Also upgrades the transitive dependencies of the listed [dependencies]
--transitive Also upgrades the transitive dependencies of the listed [dependencies]

--major-versions Upgrades packages to their latest resolvable versions, and updates pubspec.yaml.
-C, --directory=<dir> Run this in the directory <dir>.

Expand Down
126 changes: 126 additions & 0 deletions test/upgrade/upgrade_transitive_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// 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 'package:test/test.dart';

import '../descriptor.dart' as d;
import '../test_pub.dart';

void main() {
test('without --unlock-transitive, the transitive dependencies stay locked',
() async {
final server = await servePackages();
server.serve('foo', '1.0.0', deps: {'bar': '^1.0.0'});
server.serve('bar', '1.0.0');

await d.appDir(
dependencies: {
'foo': '^1.0.0',
},
).create();

await pubGet(output: contains('+ foo 1.0.0'));

server.serve('foo', '1.5.0', deps: {'bar': '^1.0.0'});
server.serve('bar', '1.5.0');

await pubUpgrade(
args: ['foo'],
output: allOf(
contains('> foo 1.5.0'),
isNot(contains('bar')),
),
);
});

test('`--unlock-transitive` dependencies gets unlocked', () async {
final server = await servePackages();
server.serve('foo', '1.0.0', deps: {'bar': '^1.0.0'});
server.serve('bar', '1.0.0');
server.serve('baz', '1.0.0');

await d.appDir(
dependencies: {
'foo': '^1.0.0',
'baz': '^1.0.0',
},
).create();

await pubGet(output: contains('+ foo 1.0.0'));

server.serve('foo', '1.5.0', deps: {'bar': '^1.0.0'});
server.serve('bar', '1.5.0');
server.serve('baz', '1.5.0');

await pubUpgrade(
args: ['--unlock-transitive', 'foo'],
output: allOf(
contains('> foo 1.5.0'),
contains('> bar 1.5.0'),
isNot(
contains('baz 1.5.0'),
), // Baz is not a transitive dependency of bar
),
);
});

test(
'`--major-versions` without `--unlock-transitive` does not allow '
'transitive dependencies to be upgraded along with the named packages',
() async {
final server = await servePackages();
server.serve('foo', '1.0.0', deps: {'bar': '^1.0.0'});
server.serve('bar', '1.0.0');

await d.appDir(
dependencies: {
'foo': '^1.0.0',
},
).create();

await pubGet(output: contains('+ foo 1.0.0'));

server.serve('foo', '2.0.0', deps: {'bar': '^1.0.0'});
server.serve('bar', '1.5.0');

await pubUpgrade(
args: ['--major-versions', 'foo'],
output: allOf(
contains('> foo 2.0.0'),
isNot(contains('bar 1.5.0')),
),
);
});

test(
'`--unlock-transitive --major-versions` allows transitive dependencies '
'be upgraded along with the named packages', () async {
final server = await servePackages();
server.serve('foo', '1.0.0', deps: {'bar': '^1.0.0'});
server.serve('bar', '1.0.0');
server.serve('baz', '1.0.0');

await d.appDir(
dependencies: {
'foo': '^1.0.0',
'baz': '^1.0.0',
},
).create();

await pubGet(output: contains('+ foo 1.0.0'));

server.serve('foo', '2.0.0', deps: {'bar': '^1.0.0'});
server.serve('bar', '1.5.0');
server.serve('baz', '1.5.0');

await pubUpgrade(
args: ['--major-versions', '--unlock-transitive', 'foo'],
output: allOf(
contains('> foo 2.0.0'),
contains('> bar 1.5.0'),
isNot(contains('> baz 1.5.0')),
),
);
});
}
Loading