diff --git a/lib/src/command/add.dart b/lib/src/command/add.dart index ddf99336bb..5a785003ab 100644 --- a/lib/src/command/add.dart +++ b/lib/src/command/add.dart @@ -349,15 +349,10 @@ Specify multiple sdk packages with descriptors.'''); dependencies.add(range); } - return Pubspec( - original.name, - version: original.version, - sdkConstraints: original.sdkConstraints, + return original.copyWith( dependencies: dependencies, devDependencies: devDependencies, dependencyOverrides: dependencyOverrides, - workspace: original.workspace, - resolution: original.resolution, ); } diff --git a/lib/src/command/dependency_services.dart b/lib/src/command/dependency_services.dart index b1f17ac96c..9e1bcf7e22 100644 --- a/lib/src/command/dependency_services.dart +++ b/lib/src/command/dependency_services.dart @@ -105,14 +105,8 @@ class DependencyServicesReportCommand extends PubCommand { ?.firstWhereOrNull((element) => element.name == package.name); final multiBreakingVersion = breakingPackagesResult ?.firstWhereOrNull((element) => element.name == package.name); - final singleBreakingPubspec = Pubspec( - compatiblePubspec.name, - version: compatiblePubspec.version, - sdkConstraints: compatiblePubspec.sdkConstraints, - dependencies: compatiblePubspec.dependencies.values, - devDependencies: compatiblePubspec.devDependencies.values, - workspace: compatiblePubspec.workspace, - ); + final singleBreakingPubspec = compatiblePubspec.copyWith(); + final dependencySet = _dependencySetOfPackage(singleBreakingPubspec, package); final kind = _kindString(compatiblePubspec, package.name); @@ -745,13 +739,7 @@ Future> _computeUpgradeSet( final pubspec = (upgradeType == _UpgradeType.multiBreaking || upgradeType == _UpgradeType.smallestUpdate) ? stripVersionBounds(rootPubspec) - : Pubspec( - rootPubspec.name, - dependencies: rootPubspec.dependencies.values, - devDependencies: rootPubspec.devDependencies.values, - sdkConstraints: rootPubspec.sdkConstraints, - workspace: rootPubspec.workspace, - ); + : rootPubspec.copyWith(); final dependencySet = _dependencySetOfPackage(pubspec, package); if (dependencySet != null) { diff --git a/lib/src/command/remove.dart b/lib/src/command/remove.dart index c2e7e32050..2dd1b79038 100644 --- a/lib/src/command/remove.dart +++ b/lib/src/command/remove.dart @@ -123,15 +123,10 @@ To remove a dependency override of a package prefix the package name with devDependencies.remove(package.name); } } - return Pubspec( - original.name, - version: original.version, - sdkConstraints: original.sdkConstraints, + return original.copyWith( dependencies: dependencies.values, devDependencies: devDependencies.values, dependencyOverrides: overrides.values, - workspace: original.workspace, - resolution: original.resolution, ); } diff --git a/lib/src/command/upgrade.dart b/lib/src/command/upgrade.dart index 1832187f64..8d3c966e46 100644 --- a/lib/src/command/upgrade.dart +++ b/lib/src/command/upgrade.dart @@ -3,9 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:async'; -import 'dart:io'; -import 'package:path/path.dart' as p; import 'package:pub_semver/pub_semver.dart'; import 'package:yaml_edit/yaml_edit.dart'; @@ -21,7 +19,6 @@ import '../pubspec_utils.dart'; import '../sdk.dart'; import '../solver.dart'; import '../source/hosted.dart'; -import '../source/root.dart'; import '../utils.dart'; /// Handles the `upgrade` pub command. @@ -141,14 +138,21 @@ Consider using the Dart 2.19 sdk to migrate to null safety.'''); await _runUpgrade(entrypoint); if (_tighten) { final changes = tighten( - entrypoint.workspaceRoot.pubspec, + entrypoint, entrypoint.lockFile.packages.values.toList(), ); if (!_dryRun) { - final newPubspecText = _updatePubspec(changes); - - if (changes.isNotEmpty) { - writeTextFile(entrypoint.workspaceRoot.pubspecPath, newPubspecText); + for (final package in entrypoint.workspaceRoot.transitiveWorkspace) { + final changesForPackage = changes[package]; + if (changesForPackage == null || changesForPackage.isEmpty) { + continue; + } + final newPubspecText = + _updatePubspecText(package, changesForPackage); + + if (changes.isNotEmpty) { + writeTextFile(package.pubspecPath, newPubspecText); + } } } _outputChangeSummary(changes); @@ -184,10 +188,10 @@ Consider using the Dart 2.19 sdk to migrate to null safety.'''); /// /// If a dependency has already been updated in [existingChanges], the update /// will apply on top of that change (eg. preserving the new upper bound). - Map tighten( - Pubspec pubspec, + Map> tighten( + Entrypoint entrypoint, List packages, { - Map existingChanges = const {}, + Map> existingChanges = const {}, }) { final result = {...existingChanges}; if (argResults.flag('example') && entrypoint.example != null) { @@ -195,27 +199,41 @@ Consider using the Dart 2.19 sdk to migrate to null safety.'''); 'Running `upgrade --tighten` only in `${entrypoint.workspaceRoot.dir}`. Run `$topLevelProgram pub upgrade --tighten --directory example/` separately.', ); } - final toTighten = _packagesToUpgrade.isEmpty - ? [ - ...pubspec.dependencies.values, - ...pubspec.devDependencies.values, - ] - : [ - for (final name in _packagesToUpgrade) - pubspec.dependencies[name] ?? pubspec.devDependencies[name], - ].nonNulls; - for (final range in toTighten) { - final constraint = (result[range] ?? range).constraint; + + final toTighten = <(Package, PackageRange)>[]; + + for (final package in entrypoint.workspaceRoot.transitiveWorkspace) { + if (_packagesToUpgrade.isEmpty) { + for (final range in [ + ...package.dependencies.values, + ...package.devDependencies.values, + ]) { + toTighten.add((package, range)); + } + } else { + for (final packageToUpgrade in _packagesToUpgrade) { + final range = package.dependencies[packageToUpgrade] ?? + package.devDependencies[packageToUpgrade]; + if (range != null) { + toTighten.add((package, range)); + } + } + } + } + + for (final (package, range) in toTighten) { + final changesForPackage = result[package] ??= {}; + final constraint = (changesForPackage[range] ?? range).constraint; final resolvedVersion = packages.firstWhere((p) => p.name == range.name).version; if (range.source is HostedSource && constraint.isAny) { - result[range] = range + changesForPackage[range] = range .toRef() .withConstraint(VersionConstraint.compatibleWith(resolvedVersion)); } else if (constraint is VersionRange) { final min = constraint.min; if (min != null && min < resolvedVersion) { - result[range] = range.toRef().withConstraint( + changesForPackage[range] = range.toRef().withConstraint( VersionRange( min: resolvedVersion, max: constraint.max, @@ -232,27 +250,24 @@ Consider using the Dart 2.19 sdk to migrate to null safety.'''); /// Return names of packages to be upgraded, and throws [UsageException] if /// any package names not in the direct dependencies or dev_dependencies are given. /// - /// This assumes that either `--major-versions` or `--null-safety` was passed. + /// This assumes that `--major-versions` was passed. List _directDependenciesToUpgrade() { assert(_upgradeMajorVersions); - final directDeps = [ - ...entrypoint.workspaceRoot.pubspec.dependencies.keys, - ...entrypoint.workspaceRoot.pubspec.devDependencies.keys, - ]; + final directDeps = { + for (final package in entrypoint.workspaceRoot.transitiveWorkspace) ...[ + ...package.dependencies.keys, + ...package.devDependencies.keys, + ], + }.toList(); final toUpgrade = _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)) { - var modeFlag = ''; - if (_upgradeMajorVersions) { - modeFlag = '--major-versions'; - } - usageException(''' -Dependencies specified in `$topLevelProgram pub upgrade $modeFlag ` must +Dependencies specified in `$topLevelProgram pub upgrade --major-versions ` must be direct 'dependencies' or 'dev_dependencies', following packages are not: - ${notInDeps.join('\n - ')} @@ -263,15 +278,11 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not: } Future _runUpgradeMajorVersions() async { - // TODO(https://github.com/dart-lang/pub/issues/4127): This should operate - // on all pubspecs in the workspace. final toUpgrade = _directDependenciesToUpgrade(); - - final resolvablePubspec = stripVersionBounds( - entrypoint.workspaceRoot.pubspec, - stripOnly: toUpgrade, - ); - + final workspace = { + for (final package in entrypoint.workspaceRoot.transitiveWorkspace) + package.dir: package, + }; // Solve [resolvablePubspec] in-memory and consolidate the resolved // versions of the packages into a map for quick searching. final resolvedPackages = {}; @@ -281,10 +292,16 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not: return await resolveVersions( SolveType.upgrade, cache, - Package( - resolvablePubspec, + Package.load( entrypoint.workspaceRoot.dir, - entrypoint.workspaceRoot.workspaceChildren, + entrypoint.cache.sources, + withPubspecOverrides: true, + loadPubspec: ( + path, { + expectedName, + required withPubspecOverrides, + }) => + stripVersionBounds(workspace[path]!.pubspec), ), ); }, @@ -293,40 +310,42 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not: for (final resolvedPackage in solveResult.packages) { resolvedPackages[resolvedPackage.name] = resolvedPackage; } - - // Changes to be made to `pubspec.yaml`. + final dependencyOverriddenDeps = []; + // Changes to be made to `pubspec.yaml` of each package. // Mapping from original to changed value. - var changes = {}; - final declaredHostedDependencies = [ - ...entrypoint.workspaceRoot.pubspec.dependencies.values, - ...entrypoint.workspaceRoot.pubspec.devDependencies.values, - ].where((dep) => dep.source is HostedSource); - for (final dep in declaredHostedDependencies) { - final resolvedPackage = resolvedPackages[dep.name]!; - if (!toUpgrade.contains(dep.name)) { - // If we're not trying to upgrade this package, or it wasn't in the - // resolution somehow, then we ignore it. - continue; - } + var changes = >{}; + for (final package in entrypoint.workspaceRoot.transitiveWorkspace) { + final declaredHostedDependencies = [ + ...package.dependencies.values, + ...package.devDependencies.values, + ].where((dep) => dep.source is HostedSource); + for (final dep in declaredHostedDependencies) { + final resolvedPackage = resolvedPackages[dep.name]!; + if (!toUpgrade.contains(dep.name)) { + // If we're not trying to upgrade this package, or it wasn't in the + // resolution somehow, then we ignore it. + continue; + } - // Skip [dep] if it has a dependency_override. - if (entrypoint.workspaceRoot.dependencyOverrides.containsKey(dep.name)) { - continue; - } + // Skip [dep] if it has a dependency_override. + if (entrypoint.workspaceRoot.dependencyOverrides + .containsKey(dep.name)) { + dependencyOverriddenDeps.add(dep.name); + continue; + } - if (dep.constraint.allowsAll(resolvedPackage.version)) { - // If constraint allows the resolvable version we found, then there is - // no need to update the `pubspec.yaml` - continue; - } + if (dep.constraint.allowsAll(resolvedPackage.version)) { + // If constraint allows the resolvable version we found, then there is + // no need to update the `pubspec.yaml` + continue; + } - changes[dep] = dep.toRef().withConstraint( - VersionConstraint.compatibleWith( - resolvedPackage.version, - ), - ); + (changes[package] ??= {})[dep] = dep.toRef().withConstraint( + VersionConstraint.compatibleWith(resolvedPackage.version), + ); + } } - var newPubspecText = _updatePubspec(changes); + if (_tighten) { // Do another solve with the updated constraints to obtain the correct // versions to tighten to. This should be fast (everything is cached, and @@ -335,18 +354,21 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not: final solveResult = await resolveVersions( SolveType.upgrade, cache, - Package( - _updatedPubspec(newPubspecText, entrypoint), + Package.load( entrypoint.workspaceRoot.dir, - entrypoint.workspaceRoot.workspaceChildren, + entrypoint.cache.sources, + loadPubspec: (path, {expectedName, required withPubspecOverrides}) { + final package = workspace[path]!; + final changesForPackage = changes[package] ?? {}; + return applyChanges(package.pubspec, changesForPackage); + }, ), ); changes = tighten( - entrypoint.workspaceRoot.pubspec, + entrypoint, solveResult.packages, existingChanges: changes, ); - newPubspecText = _updatePubspec(changes); } // When doing '--majorVersions' for specific packages we try to update other @@ -358,18 +380,23 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not: _packagesToUpgrade.isEmpty ? SolveType.upgrade : SolveType.get; if (!_dryRun) { - if (changes.isNotEmpty) { - writeTextFile(entrypoint.workspaceRoot.pubspecPath, newPubspecText); + for (final package in entrypoint.workspaceRoot.transitiveWorkspace) { + final changesForPackage = changes[package] ?? {}; + if (changesForPackage.isNotEmpty) { + final newPubspecText = _updatePubspecText(package, changesForPackage); + writeTextFile(package.pubspecPath, newPubspecText); + } } } - - await entrypoint - .withWorkPubspec(_updatedPubspec(newPubspecText, entrypoint)) - .acquireDependencies( - solveType, - dryRun: _dryRun, - precompile: !_dryRun && _precompile, - ); + await entrypoint.withUpdatedPubspecs({ + for (final MapEntry(key: package, value: changesForPackage) + in changes.entries) + package: applyChanges(package.pubspec, changesForPackage), + }).acquireDependencies( + solveType, + dryRun: _dryRun, + precompile: !_dryRun && _precompile, + ); _outputChangeSummary(changes); @@ -387,59 +414,82 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not: _showOfflineWarning(); } - Pubspec _updatedPubspec(String contents, Entrypoint entrypoint) { - String? overridesFileContents; - final overridesPath = - p.join(entrypoint.workspaceRoot.dir, Pubspec.pubspecOverridesFilename); - try { - overridesFileContents = readTextFile(overridesPath); - } on IOException { - overridesFileContents = null; + Pubspec applyChanges( + Pubspec original, + Map changes, + ) { + final dependencies = {...original.dependencies}; + final devDependencies = {...original.devDependencies}; + + for (final change in changes.values) { + if (dependencies[change.name] != null) { + dependencies[change.name] = change; + } else { + devDependencies[change.name] = change; + } } - return Pubspec.parse( - contents, - cache.sources, - location: Uri.parse(entrypoint.workspaceRoot.pubspecPath), - overridesFileContents: overridesFileContents, - overridesLocation: Uri.file(overridesPath), - containingDescription: RootDescription(entrypoint.workspaceRoot.dir), + return original.copyWith( + dependencies: dependencies.values, + devDependencies: devDependencies.values, ); } - /// Updates `pubspec.yaml` with given [changes]. - String _updatePubspec( + /// Loads `pubspec.yaml` of [package] and applies [changes] to its + /// (dev)-dependencies. + /// + /// Returns the updated textual representation using yaml-edit to preserve + /// structure. + String _updatePubspecText( + Package package, Map changes, ) { ArgumentError.checkNotNull(changes, 'changes'); - final yamlEditor = - YamlEditor(readTextFile(entrypoint.workspaceRoot.pubspecPath)); - final deps = entrypoint.workspaceRoot.pubspec.dependencies.keys; + final yamlEditor = YamlEditor(readTextFile(package.pubspecPath)); + final deps = package.dependencies.keys; for (final change in changes.values) { final section = deps.contains(change.name) ? 'dependencies' : 'dev_dependencies'; yamlEditor.update( [section, change.name], - pubspecDescription(change, cache, entrypoint.workspaceRoot), + pubspecDescription(change, cache, package), ); } return yamlEditor.toString(); } /// Outputs a summary of changes made to `pubspec.yaml`. - void _outputChangeSummary(Map changes) { - ArgumentError.checkNotNull(changes, 'changes'); - - if (changes.isEmpty) { - final wouldBe = _dryRun ? 'would be made to' : 'to'; - log.message('\nNo changes $wouldBe pubspec.yaml!'); + void _outputChangeSummary( + Map> changes, + ) { + if (entrypoint.workspaceRoot.workspaceChildren.isEmpty) { + final changesToWorkspaceRoot = changes[entrypoint.workspaceRoot] ?? {}; + if (changesToWorkspaceRoot.isEmpty) { + final wouldBe = _dryRun ? 'would be made to' : 'to'; + log.message('\nNo changes $wouldBe pubspec.yaml!'); + } else { + final changed = _dryRun ? 'Would change' : 'Changed'; + log.message('\n$changed ${changesToWorkspaceRoot.length} ' + '${pluralize('constraint', changesToWorkspaceRoot.length)} in pubspec.yaml:'); + changesToWorkspaceRoot.forEach((from, to) { + log.message(' ${from.name}: ${from.constraint} -> ${to.constraint}'); + }); + } } else { - final changed = _dryRun ? 'Would change' : 'Changed'; - log.message('\n$changed ${changes.length} ' - '${pluralize('constraint', changes.length)} in pubspec.yaml:'); - changes.forEach((from, to) { - log.message(' ${from.name}: ${from.constraint} -> ${to.constraint}'); - }); + if (changes.isEmpty) { + final wouldBe = _dryRun ? 'would be made to' : 'to'; + log.message('\nNo changes $wouldBe any pubspec.yaml!'); + } + for (final package in entrypoint.workspaceRoot.transitiveWorkspace) { + final changesToPackage = changes[package] ?? {}; + if (changesToPackage.isEmpty) continue; + final changed = _dryRun ? 'Would change' : 'Changed'; + log.message('\n$changed ${changesToPackage.length} ' + '${pluralize('constraint', changesToPackage.length)} in ${package.pubspecPath}:'); + changesToPackage.forEach((from, to) { + log.message(' ${from.name}: ${from.constraint} -> ${to.constraint}'); + }); + } } } diff --git a/lib/src/entrypoint.dart b/lib/src/entrypoint.dart index bc809a82a0..861c9df695 100644 --- a/lib/src/entrypoint.dart +++ b/lib/src/entrypoint.dart @@ -334,16 +334,15 @@ See $workspacesDocUrl for more information.''', } } - /// Creates an entrypoint at the same location, that will use [pubspec] for - /// resolution of the [workPackage]. - Entrypoint withWorkPubspec(Pubspec pubspec) { + /// Creates an entrypoint at the same location, but with each pubspec in + /// [updatedPubspec] replacing the with one for the corresponding package. + Entrypoint withUpdatedPubspecs(Map updatedPubspecs) { final existingPubspecs = {}; // First extract all pubspecs from the workspace. for (final package in workspaceRoot.transitiveWorkspace) { - existingPubspecs[package.dir] = package.pubspec; + existingPubspecs[package.dir] = + updatedPubspecs[package] ?? package.pubspec; } - // Then override the one of the workPackage. - existingPubspecs[p.canonicalize(workPackage.dir)] = pubspec; final newWorkspaceRoot = Package.load( workspaceRoot.dir, cache.sources, @@ -352,7 +351,7 @@ See $workspacesDocUrl for more information.''', expectedName, required withPubspecOverrides, }) => - existingPubspecs[p.canonicalize(dir)] ?? + existingPubspecs[dir] ?? Pubspec.load( dir, cache.sources, @@ -372,6 +371,12 @@ See $workspacesDocUrl for more information.''', ); } + /// Creates an entrypoint at the same location, that will use [pubspec] for + /// resolution of the [workPackage]. + Entrypoint withWorkPubspec(Pubspec pubspec) { + return withUpdatedPubspecs({workPackage: pubspec}); + } + /// Creates an entrypoint given package and lockfile objects. /// If a SolveResult is already created it can be passed as an optimization. Entrypoint.global( diff --git a/lib/src/package.dart b/lib/src/package.dart index d7f8642ccf..ca6b3f6fbb 100644 --- a/lib/src/package.dart +++ b/lib/src/package.dart @@ -64,7 +64,10 @@ class Package { while (stack.isNotEmpty) { final current = stack.removeLast(); yield current; - stack.addAll(current.workspaceChildren); + // Because we pick from the end of the stack, elements are added in + // reverse, such that they will be visited in the order they appear in the + // list. + stack.addAll(current.workspaceChildren.reversed); } } diff --git a/lib/src/pubspec.dart b/lib/src/pubspec.dart index a67a89400b..2a951ad8a3 100644 --- a/lib/src/pubspec.dart +++ b/lib/src/pubspec.dart @@ -407,6 +407,31 @@ class Pubspec extends PubspecBase { ); } + Pubspec copyWith({ + String? name, + Version? version, + Iterable? dependencies, + Iterable? devDependencies, + Iterable? dependencyOverrides, + Map? fields, + Map? sdkConstraints, + List? workspace, + //this.dependencyOverridesFromOverridesFile = false, + Resolution? resolution, + }) { + return Pubspec( + name ?? this.name, + version: version ?? this.version, + dependencies: dependencies ?? this.dependencies.values, + devDependencies: devDependencies ?? this.devDependencies.values, + dependencyOverrides: + dependencyOverrides ?? this.dependencyOverrides.values, + sdkConstraints: sdkConstraints ?? this.sdkConstraints, + workspace: workspace ?? this.workspace, + resolution: resolution ?? this.resolution, + ); + } + /// Ensures that [node] is a mapping. /// /// If [node] is already a map it is returned. diff --git a/lib/src/pubspec_utils.dart b/lib/src/pubspec_utils.dart index 74b2ce8e26..646114c931 100644 --- a/lib/src/pubspec_utils.dart +++ b/lib/src/pubspec_utils.dart @@ -13,32 +13,12 @@ import 'system_cache.dart'; /// Returns a new [Pubspec] without [original]'s dev_dependencies. Pubspec stripDevDependencies(Pubspec original) { - ArgumentError.checkNotNull(original, 'original'); - - return Pubspec( - original.name, - version: original.version, - sdkConstraints: original.sdkConstraints, - dependencies: original.dependencies.values, - devDependencies: [], // explicitly give empty list, to prevent lazy parsing - dependencyOverrides: original.dependencyOverrides.values, - workspace: original.workspace, - ); + return original.copyWith(devDependencies: []); } /// Returns a new [Pubspec] without [original]'s dependency_overrides. Pubspec stripDependencyOverrides(Pubspec original) { - ArgumentError.checkNotNull(original, 'original'); - - return Pubspec( - original.name, - version: original.version, - sdkConstraints: original.sdkConstraints, - dependencies: original.dependencies.values, - devDependencies: original.devDependencies.values, - dependencyOverrides: [], - workspace: original.workspace, - ); + return original.copyWith(dependencyOverrides: []); } /// Returns new pubspec with the same dependencies as [original] but with the @@ -54,7 +34,6 @@ Pubspec stripVersionBounds( Iterable? stripOnly, bool stripLowerBound = false, }) { - ArgumentError.checkNotNull(original, 'original'); stripOnly ??= []; List stripBounds( @@ -80,14 +59,9 @@ Pubspec stripVersionBounds( return result; } - return Pubspec( - original.name, - version: original.version, - sdkConstraints: original.sdkConstraints, + return original.copyWith( dependencies: stripBounds(original.dependencies), devDependencies: stripBounds(original.devDependencies), - dependencyOverrides: original.dependencyOverrides.values, - workspace: original.workspace, ); } @@ -117,14 +91,9 @@ Pubspec atLeastCurrent(Pubspec original, List current) { return result; } - return Pubspec( - original.name, - version: original.version, - sdkConstraints: original.sdkConstraints, + return original.copyWith( dependencies: fixBounds(original.dependencies), devDependencies: fixBounds(original.devDependencies), - dependencyOverrides: original.dependencyOverrides.values, - workspace: original.workspace, ); } diff --git a/test/workspace_test.dart b/test/workspace_test.dart index 7bf863834b..967c7379b8 100644 --- a/test/workspace_test.dart +++ b/test/workspace_test.dart @@ -478,24 +478,24 @@ dependencies: - myapp any - both ^1.0.0 -b 1.1.1 +a 1.1.1 dependencies: - myapp 1.2.3 - both ^1.0.0 - b any +- foo 1.0.0 + - transitive ^1.0.0 + +dev dependencies: - both 1.0.0 -a 1.1.1 +b 1.1.1 dependencies: - myapp 1.2.3 - both ^1.0.0 - b any -- foo 1.0.0 - - transitive ^1.0.0 - -dev dependencies: - both 1.0.0 transitive dependencies: @@ -515,22 +515,22 @@ dependencies: - myapp any - both ^1.0.0 -b 1.1.1 +a 1.1.1 dependencies: - myapp 1.2.3 - both ^1.0.0 - b any -- both 1.0.0 +- foo 1.0.0 + - transitive ^1.0.0 -a 1.1.1 +b 1.1.1 dependencies: - myapp 1.2.3 - both ^1.0.0 - b any -- foo 1.0.0 - - transitive ^1.0.0 +- both 1.0.0 transitive dependencies: - transitive 1.0.0''', @@ -546,12 +546,6 @@ dependencies: - b 1.1.1 [myapp both] - both 1.0.0 -b 1.1.1 - -dependencies: -- both 1.0.0 -- myapp 1.2.3 [both b] - a 1.1.1 dependencies: @@ -561,6 +555,12 @@ dependencies: dev dependencies: - both 1.0.0 +b 1.1.1 + +dependencies: +- both 1.0.0 +- myapp 1.2.3 [both b] + transitive dependencies: - transitive 1.0.0''', ); @@ -775,4 +775,322 @@ foo:foomain''', exitCode: DATA, ); }); + + test('`upgrade` upgrades all workspace', () async { + final server = await servePackages(); + server.serve('foo', '1.0.0'); + server.serve('bar', '1.0.0'); + await dir(appPath, [ + libPubspec( + 'myapp', + '1.2.3', + deps: {'foo': '^1.0.0'}, + sdk: '^3.7.0', + extras: { + 'workspace': ['a'], + }, + ), + dir('a', [ + libPubspec( + 'a', + '1.0.0', + deps: {'bar': '^1.0.0'}, + resolutionWorkspace: true, + ), + ]), + ]).create(); + await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'}); + server.serve('foo', '1.5.0'); + server.serve('bar', '1.5.0'); + await pubUpgrade( + environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'}, + output: contains( + ''' +> bar 1.5.0 (was 1.0.0) +> foo 1.5.0 (was 1.0.0)''', + ), + ); + }); + + test('`upgrade --major-versions` upgrades all workspace', () async { + final server = await servePackages(); + server.serve('foo', '1.5.0'); + server.serve('foo', '2.0.0'); + server.serve('bar', '1.0.0'); + server.serve('bar', '2.0.0'); + await dir(appPath, [ + libPubspec( + 'myapp', + '1.2.3', + deps: {'foo': '^1.0.0', 'bar': '1.0.0'}, + sdk: '^3.7.0', + extras: { + 'workspace': ['a'], + }, + ), + dir('a', [ + libPubspec( + 'a', + '1.0.0', + deps: {'foo': '1.5.0'}, + resolutionWorkspace: true, + ), + ]), + ]).create(); + + await pubGet( + environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'}, + output: contains('+ foo 1.5.0'), + ); + await pubUpgrade( + args: ['--major-versions'], + environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'}, + output: contains( + ''' +Changed 2 constraints in pubspec.yaml: + foo: ^1.0.0 -> ^2.0.0 + bar: 1.0.0 -> ^2.0.0 + +Changed 1 constraint in a${s}pubspec.yaml: + foo: 1.5.0 -> ^2.0.0''', + ), + ); + + await dir(appPath, [ + libPubspec( + 'myapp', + '1.2.3', + deps: {'foo': '^2.0.0', 'bar': '^2.0.0'}, + sdk: '^3.7.0', + extras: { + 'workspace': ['a'], + }, + ), + dir('a', [ + libPubspec( + 'a', + '1.0.0', + deps: {'foo': '^2.0.0'}, + resolutionWorkspace: true, + ), + ]), + ]).validate(); + }); + test('`upgrade --major-versions foo` upgrades foo in all workspace', + () async { + final server = await servePackages(); + server.serve('foo', '1.5.0'); + server.serve('foo', '2.0.0'); + server.serve('bar', '1.0.0'); + server.serve('bar', '2.0.0'); + await dir(appPath, [ + libPubspec( + 'myapp', + '1.2.3', + deps: {'foo': '^1.0.0', 'bar': '1.0.0'}, + sdk: '^3.7.0', + extras: { + 'workspace': ['a'], + }, + ), + dir('a', [ + libPubspec( + 'a', + '1.0.0', + deps: {'foo': '1.5.0'}, + resolutionWorkspace: true, + ), + ]), + ]).create(); + + await pubGet( + environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'}, + output: contains('+ foo 1.5.0'), + ); + await pubUpgrade( + args: ['--major-versions', 'foo'], + environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'}, + output: contains( + ''' +Changed 1 constraint in pubspec.yaml: + foo: ^1.0.0 -> ^2.0.0 + +Changed 1 constraint in a${s}pubspec.yaml: + foo: 1.5.0 -> ^2.0.0''', + ), + ); + // Second run should mention "any pubspec.yaml". + await pubUpgrade( + args: ['--major-versions', 'foo'], + environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'}, + output: contains( + ''' +No changes to any pubspec.yaml!''', + ), + ); + await pubUpgrade( + args: ['--major-versions', 'foo', '--dry-run'], + environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'}, + output: contains( + ''' +No changes would be made to any pubspec.yaml!''', + ), + ); + + await dir(appPath, [ + libPubspec( + 'myapp', + '1.2.3', + deps: {'foo': '^2.0.0', 'bar': '1.0.0'}, + sdk: '^3.7.0', + extras: { + 'workspace': ['a'], + }, + ), + dir('a', [ + libPubspec( + 'a', + '1.0.0', + deps: {'foo': '^2.0.0'}, + resolutionWorkspace: true, + ), + ]), + ]).validate(); + }); + + test('`upgrade --tighten` updates all workspace', () async { + final server = await servePackages(); + server.serve('foo', '1.5.0'); + server.serve('bar', '1.5.0'); + await dir(appPath, [ + libPubspec( + 'myapp', + '1.2.3', + deps: {'foo': '^1.0.0', 'bar': '^1.0.0'}, + sdk: '^3.7.0', + extras: { + 'workspace': ['a', 'b'], + }, + ), + dir('a', [ + libPubspec( + 'a', + '1.0.0', + deps: {'foo': '^1.0.0'}, + resolutionWorkspace: true, + ), + ]), + dir('b', [ + libPubspec( + 'b', + '1.0.0', + deps: {'bar': '^1.5.0'}, + resolutionWorkspace: true, + ), + ]), + ]).create(); + + await pubGet( + environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'}, + output: contains('+ foo 1.5.0'), + ); + await pubUpgrade( + args: ['--tighten'], + environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'}, + output: contains( + ''' +Changed 2 constraints in pubspec.yaml: + foo: ^1.0.0 -> ^1.5.0 + bar: ^1.0.0 -> ^1.5.0 + +Changed 1 constraint in a${s}pubspec.yaml: + foo: ^1.0.0 -> ^1.5.0''', + ), + ); + + await dir(appPath, [ + libPubspec( + 'myapp', + '1.2.3', + deps: {'foo': '^1.5.0', 'bar': '^1.5.0'}, + sdk: '^3.7.0', + extras: { + 'workspace': ['a', 'b'], + }, + ), + dir('a', [ + libPubspec( + 'a', + '1.0.0', + deps: {'foo': '^1.5.0'}, + resolutionWorkspace: true, + ), + ]), + dir('b', [ + libPubspec( + 'b', + '1.0.0', + deps: {'bar': '^1.5.0'}, + resolutionWorkspace: true, + ), + ]), + ]).validate(); + }); + + test('`upgrade --major-versions --tighten` updates all workspace', () async { + final server = await servePackages(); + server.serve('foo', '1.5.0'); + server.serve('bar', '1.5.0'); + server.serve('foo', '2.0.0'); + await dir(appPath, [ + libPubspec( + 'myapp', + '1.2.3', + deps: {'foo': '^1.0.0', 'bar': '^1.0.0'}, + sdk: '^3.7.0', + extras: { + 'workspace': ['a', 'b'], + }, + ), + dir('a', [ + libPubspec( + 'a', + '1.0.0', + deps: {'foo': '^1.0.0'}, + resolutionWorkspace: true, + ), + ]), + dir('b', [ + libPubspec( + 'b', + '1.0.0', + deps: {'bar': '^1.0.0'}, + resolutionWorkspace: true, + ), + ]), + ]).create(); + + await pubGet( + environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'}, + output: contains('+ foo 1.5.0'), + ); + await pubUpgrade( + args: ['--tighten', '--major-versions'], + environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'}, + output: contains( + ''' +Changed 2 constraints in pubspec.yaml: + foo: ^1.0.0 -> ^2.0.0 + bar: ^1.0.0 -> ^1.5.0 + +Changed 1 constraint in a${s}pubspec.yaml: + foo: ^1.0.0 -> ^2.0.0 + +Changed 1 constraint in b${s}pubspec.yaml: + bar: ^1.0.0 -> ^1.5.0''', + ), + ); + }); } + +final s = p.separator;