Respect upper bound of Flutter constraint in root packages after 3.9 (#4595)
diff --git a/lib/src/language_version.dart b/lib/src/language_version.dart
index fdfb2bf..0f5fffa 100644
--- a/lib/src/language_version.dart
+++ b/lib/src/language_version.dart
@@ -70,6 +70,9 @@
bool get forbidsUnknownDescriptionKeys =>
this >= firstVersionForbidingUnknownDescriptionKeys;
+ bool get respectsFlutterBoundInRoots =>
+ this >= firstVersionRespectingFlutterBoundInRoots;
+
/// Minimum language version at which short hosted syntax is supported.
///
/// This allows `hosted` dependencies to be expressed as:
@@ -112,6 +115,10 @@
3,
7,
);
+ static const firstVersionRespectingFlutterBoundInRoots = LanguageVersion(
+ 3,
+ 9,
+ );
/// Transform language version to string that can be parsed with
/// [LanguageVersion.parse].
diff --git a/lib/src/lock_file.dart b/lib/src/lock_file.dart
index dc688e9..f514406 100644
--- a/lib/src/lock_file.dart
+++ b/lib/src/lock_file.dart
@@ -10,6 +10,7 @@
import 'package:yaml/yaml.dart';
import 'io.dart';
+import 'language_version.dart';
import 'package_name.dart';
import 'pubspec.dart';
import 'system_cache.dart';
@@ -149,6 +150,8 @@
),
'flutter' => SdkConstraint.interpretFlutterSdkConstraint(
originalConstraint,
+ isRoot: false,
+ languageVersion: LanguageVersion.defaultLanguageVersion,
),
_ => SdkConstraint(originalConstraint),
};
diff --git a/lib/src/pubspec.dart b/lib/src/pubspec.dart
index 5ebc55f..62eaeb9 100644
--- a/lib/src/pubspec.dart
+++ b/lib/src/pubspec.dart
@@ -225,15 +225,12 @@
_FileType.pubspec,
);
}
- final constraints = {
- 'dart': SdkConstraint.interpretDartSdkConstraint(
- originalDartSdkConstraint,
- defaultUpperBoundConstraint:
- _includeDefaultSdkConstraint
- ? _defaultUpperBoundSdkConstraint
- : null,
- ),
- };
+ final dartConstraint = SdkConstraint.interpretDartSdkConstraint(
+ originalDartSdkConstraint,
+ defaultUpperBoundConstraint:
+ _includeDefaultSdkConstraint ? _defaultUpperBoundSdkConstraint : null,
+ );
+ final constraints = {'dart': dartConstraint};
if (yaml is YamlMap) {
yaml.nodes.forEach((nameNode, constraintNode) {
@@ -253,7 +250,11 @@
);
constraints[name] =
name == 'flutter'
- ? SdkConstraint.interpretFlutterSdkConstraint(constraint)
+ ? SdkConstraint.interpretFlutterSdkConstraint(
+ constraint,
+ isRoot: _containingDescription is ResolvedRootDescription,
+ languageVersion: dartConstraint.languageVersion,
+ )
: SdkConstraint(constraint);
});
}
@@ -816,17 +817,26 @@
return SdkConstraint(constraint, originalConstraint: originalConstraint);
}
- // Flutter constraints get special treatment, as Flutter won't be using
- // semantic versioning to mark breaking releases. We simply ignore upper
- // bounds.
+ /// Flutter constraints get special treatment, as Flutter won't be using
+ /// semantic versioning to mark breaking releases. We simply ignore upper
+ /// bounds for dependencies.
+ ///
+ /// After language version
+ /// [LanguageVersion.firstVersionRespectingFlutterBoundInRoots] for root
+ /// packages we use the upper bound, allowing app developers to constrain the
+ /// Flutter version.
factory SdkConstraint.interpretFlutterSdkConstraint(
- VersionConstraint constraint,
- ) {
+ VersionConstraint constraint, {
+ required bool isRoot,
+ required LanguageVersion languageVersion,
+ }) {
if (constraint is VersionRange) {
- return SdkConstraint(
- VersionRange(min: constraint.min, includeMin: constraint.includeMin),
- originalConstraint: constraint,
- );
+ if (!(isRoot && languageVersion.respectsFlutterBoundInRoots)) {
+ return SdkConstraint(
+ VersionRange(min: constraint.min, includeMin: constraint.includeMin),
+ originalConstraint: constraint,
+ );
+ }
}
return SdkConstraint(constraint);
}
diff --git a/test/get/flutter_constraint_upper_bound_ignored_test.dart b/test/get/flutter_constraint_upper_bound_ignored_test.dart
index 3491746..0620211 100644
--- a/test/get/flutter_constraint_upper_bound_ignored_test.dart
+++ b/test/get/flutter_constraint_upper_bound_ignored_test.dart
@@ -9,21 +9,116 @@
import '../test_pub.dart';
void main() {
- test('pub get succeeds despite of "invalid" flutter upper bound', () async {
+ test(
+ 'pub get succeeds despite of "invalid" flutter upper bound in dependency',
+ () async {
+ final fakeFlutterRoot = d.dir('fake_flutter_root', [
+ d.flutterVersion('1.23.0'),
+ ]);
+ await fakeFlutterRoot.create();
+
+ final server = await servePackages();
+ server.serve(
+ 'foo',
+ '1.0.0',
+ pubspec: {
+ 'environment': {'sdk': '^$testVersion', 'flutter': '>=0.5.0 <1.0.0'},
+ },
+ );
+
+ await d.appDir(dependencies: {'foo': '^1.0.0'}).create();
+
+ await pubGet(
+ exitCode: exit_codes.SUCCESS,
+ environment: {'FLUTTER_ROOT': fakeFlutterRoot.io.path},
+ );
+ },
+ );
+
+ test('pub get ignores the bound of the root package before 3.10', () async {
final fakeFlutterRoot = d.dir('fake_flutter_root', [
d.flutterVersion('1.23.0'),
]);
await fakeFlutterRoot.create();
+
+ await d
+ .appDir(
+ pubspec: {
+ 'environment': {'sdk': '^3.8.0', 'flutter': '>=0.5.0 <1.0.0'},
+ },
+ )
+ .create();
+
+ await pubGet(
+ environment: {
+ 'FLUTTER_ROOT': fakeFlutterRoot.io.path,
+ '_PUB_TEST_SDK_VERSION': '3.9.0',
+ },
+ );
+ });
+
+ test('pub get respects the bound of the root package after 3.9', () async {
+ final fakeFlutterRoot = d.dir('fake_flutter_root', [
+ d.flutterVersion('1.23.0'),
+ ]);
+ await fakeFlutterRoot.create();
+
+ await d
+ .appDir(
+ pubspec: {
+ 'environment': {'sdk': '^3.9.0', 'flutter': '>=0.5.0 <1.0.0'},
+ },
+ )
+ .create();
+
+ await pubGet(
+ exitCode: 1,
+ environment: {
+ 'FLUTTER_ROOT': fakeFlutterRoot.io.path,
+ '_PUB_TEST_SDK_VERSION': '3.9.0',
+ },
+ error: contains(
+ 'Because myapp requires '
+ 'Flutter SDK version >=0.5.0 <1.0.0, version solving failed',
+ ),
+ );
+ });
+
+ test('pub get respects the bound of a workspace root package', () async {
+ final fakeFlutterRoot = d.dir('fake_flutter_root', [
+ d.flutterVersion('1.23.0'),
+ ]);
+ await fakeFlutterRoot.create();
+
await d.dir(appPath, [
- d.pubspec({
- 'name': 'myapp',
- 'environment': {'flutter': '>=0.5.0 <1.0.0'},
- }),
+ d.appPubspec(
+ extras: {
+ 'environment': {'sdk': '^3.9.0'},
+ 'workspace': ['app'],
+ },
+ ),
+ d.dir('app', [
+ d.libPubspec(
+ 'app',
+ '1.0.0',
+ resolutionWorkspace: true,
+ extras: {
+ 'environment': {'sdk': '^3.9.0', 'flutter': '>=0.5.0 <1.0.0'},
+ },
+ ),
+ ]),
]).create();
await pubGet(
- exitCode: exit_codes.SUCCESS,
- environment: {'FLUTTER_ROOT': fakeFlutterRoot.io.path},
+ exitCode: 1,
+ environment: {
+ '_PUB_TEST_SDK_VERSION': '3.9.0',
+ 'FLUTTER_ROOT': fakeFlutterRoot.io.path,
+ },
+ error: contains(
+ 'Because app requires '
+ 'Flutter SDK version >=0.5.0 <1.0.0, version solving failed',
+ ),
);
});
}
diff --git a/test/pubspec_test.dart b/test/pubspec_test.dart
index a3e2ba3..11892a1 100644
--- a/test/pubspec_test.dart
+++ b/test/pubspec_test.dart
@@ -793,7 +793,7 @@
final pubspec = Pubspec.parse(
'''
environment:
- sdk: ">=1.2.3 <2.3.4"
+ sdk: ">=3.10.3 <3.11.4"
flutter: ^0.1.2
fuchsia: ^5.6.7
''',
@@ -804,17 +804,14 @@
pubspec.sdkConstraints,
containsPair(
'dart',
- SdkConstraint(VersionConstraint.parse('>=1.2.3 <2.3.4')),
+ SdkConstraint(VersionConstraint.parse('>=3.10.3 <3.11.4')),
),
);
expect(
pubspec.sdkConstraints,
containsPair(
'flutter',
- SdkConstraint(
- VersionConstraint.parse('>=0.1.2'),
- originalConstraint: VersionConstraint.parse('^0.1.2'),
- ),
+ SdkConstraint(VersionConstraint.parse('^0.1.2')),
),
);
expect(