Skip to content

Commit 27c64ba

Browse files
authored
Respect upper bound of Flutter constraint in root packages after 3.9 (#4595)
1 parent cc427f5 commit 27c64ba

File tree

5 files changed

+144
-32
lines changed

5 files changed

+144
-32
lines changed

lib/src/language_version.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ class LanguageVersion implements Comparable<LanguageVersion> {
7070
bool get forbidsUnknownDescriptionKeys =>
7171
this >= firstVersionForbidingUnknownDescriptionKeys;
7272

73+
bool get respectsFlutterBoundInRoots =>
74+
this >= firstVersionRespectingFlutterBoundInRoots;
75+
7376
/// Minimum language version at which short hosted syntax is supported.
7477
///
7578
/// This allows `hosted` dependencies to be expressed as:
@@ -112,6 +115,10 @@ class LanguageVersion implements Comparable<LanguageVersion> {
112115
3,
113116
7,
114117
);
118+
static const firstVersionRespectingFlutterBoundInRoots = LanguageVersion(
119+
3,
120+
9,
121+
);
115122

116123
/// Transform language version to string that can be parsed with
117124
/// [LanguageVersion.parse].

lib/src/lock_file.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'package:source_span/source_span.dart';
1010
import 'package:yaml/yaml.dart';
1111

1212
import 'io.dart';
13+
import 'language_version.dart';
1314
import 'package_name.dart';
1415
import 'pubspec.dart';
1516
import 'system_cache.dart';
@@ -149,6 +150,8 @@ class LockFile {
149150
),
150151
'flutter' => SdkConstraint.interpretFlutterSdkConstraint(
151152
originalConstraint,
153+
isRoot: false,
154+
languageVersion: LanguageVersion.defaultLanguageVersion,
152155
),
153156
_ => SdkConstraint(originalConstraint),
154157
};

lib/src/pubspec.dart

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -225,15 +225,12 @@ environment:
225225
_FileType.pubspec,
226226
);
227227
}
228-
final constraints = {
229-
'dart': SdkConstraint.interpretDartSdkConstraint(
230-
originalDartSdkConstraint,
231-
defaultUpperBoundConstraint:
232-
_includeDefaultSdkConstraint
233-
? _defaultUpperBoundSdkConstraint
234-
: null,
235-
),
236-
};
228+
final dartConstraint = SdkConstraint.interpretDartSdkConstraint(
229+
originalDartSdkConstraint,
230+
defaultUpperBoundConstraint:
231+
_includeDefaultSdkConstraint ? _defaultUpperBoundSdkConstraint : null,
232+
);
233+
final constraints = {'dart': dartConstraint};
237234

238235
if (yaml is YamlMap) {
239236
yaml.nodes.forEach((nameNode, constraintNode) {
@@ -253,7 +250,11 @@ environment:
253250
);
254251
constraints[name] =
255252
name == 'flutter'
256-
? SdkConstraint.interpretFlutterSdkConstraint(constraint)
253+
? SdkConstraint.interpretFlutterSdkConstraint(
254+
constraint,
255+
isRoot: _containingDescription is ResolvedRootDescription,
256+
languageVersion: dartConstraint.languageVersion,
257+
)
257258
: SdkConstraint(constraint);
258259
});
259260
}
@@ -816,17 +817,26 @@ class SdkConstraint {
816817
return SdkConstraint(constraint, originalConstraint: originalConstraint);
817818
}
818819

819-
// Flutter constraints get special treatment, as Flutter won't be using
820-
// semantic versioning to mark breaking releases. We simply ignore upper
821-
// bounds.
820+
/// Flutter constraints get special treatment, as Flutter won't be using
821+
/// semantic versioning to mark breaking releases. We simply ignore upper
822+
/// bounds for dependencies.
823+
///
824+
/// After language version
825+
/// [LanguageVersion.firstVersionRespectingFlutterBoundInRoots] for root
826+
/// packages we use the upper bound, allowing app developers to constrain the
827+
/// Flutter version.
822828
factory SdkConstraint.interpretFlutterSdkConstraint(
823-
VersionConstraint constraint,
824-
) {
829+
VersionConstraint constraint, {
830+
required bool isRoot,
831+
required LanguageVersion languageVersion,
832+
}) {
825833
if (constraint is VersionRange) {
826-
return SdkConstraint(
827-
VersionRange(min: constraint.min, includeMin: constraint.includeMin),
828-
originalConstraint: constraint,
829-
);
834+
if (!(isRoot && languageVersion.respectsFlutterBoundInRoots)) {
835+
return SdkConstraint(
836+
VersionRange(min: constraint.min, includeMin: constraint.includeMin),
837+
originalConstraint: constraint,
838+
);
839+
}
830840
}
831841
return SdkConstraint(constraint);
832842
}

test/get/flutter_constraint_upper_bound_ignored_test.dart

Lines changed: 102 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,116 @@ import '../descriptor.dart' as d;
99
import '../test_pub.dart';
1010

1111
void main() {
12-
test('pub get succeeds despite of "invalid" flutter upper bound', () async {
12+
test(
13+
'pub get succeeds despite of "invalid" flutter upper bound in dependency',
14+
() async {
15+
final fakeFlutterRoot = d.dir('fake_flutter_root', [
16+
d.flutterVersion('1.23.0'),
17+
]);
18+
await fakeFlutterRoot.create();
19+
20+
final server = await servePackages();
21+
server.serve(
22+
'foo',
23+
'1.0.0',
24+
pubspec: {
25+
'environment': {'sdk': '^$testVersion', 'flutter': '>=0.5.0 <1.0.0'},
26+
},
27+
);
28+
29+
await d.appDir(dependencies: {'foo': '^1.0.0'}).create();
30+
31+
await pubGet(
32+
exitCode: exit_codes.SUCCESS,
33+
environment: {'FLUTTER_ROOT': fakeFlutterRoot.io.path},
34+
);
35+
},
36+
);
37+
38+
test('pub get ignores the bound of the root package before 3.10', () async {
1339
final fakeFlutterRoot = d.dir('fake_flutter_root', [
1440
d.flutterVersion('1.23.0'),
1541
]);
1642
await fakeFlutterRoot.create();
43+
44+
await d
45+
.appDir(
46+
pubspec: {
47+
'environment': {'sdk': '^3.8.0', 'flutter': '>=0.5.0 <1.0.0'},
48+
},
49+
)
50+
.create();
51+
52+
await pubGet(
53+
environment: {
54+
'FLUTTER_ROOT': fakeFlutterRoot.io.path,
55+
'_PUB_TEST_SDK_VERSION': '3.9.0',
56+
},
57+
);
58+
});
59+
60+
test('pub get respects the bound of the root package after 3.9', () async {
61+
final fakeFlutterRoot = d.dir('fake_flutter_root', [
62+
d.flutterVersion('1.23.0'),
63+
]);
64+
await fakeFlutterRoot.create();
65+
66+
await d
67+
.appDir(
68+
pubspec: {
69+
'environment': {'sdk': '^3.9.0', 'flutter': '>=0.5.0 <1.0.0'},
70+
},
71+
)
72+
.create();
73+
74+
await pubGet(
75+
exitCode: 1,
76+
environment: {
77+
'FLUTTER_ROOT': fakeFlutterRoot.io.path,
78+
'_PUB_TEST_SDK_VERSION': '3.9.0',
79+
},
80+
error: contains(
81+
'Because myapp requires '
82+
'Flutter SDK version >=0.5.0 <1.0.0, version solving failed',
83+
),
84+
);
85+
});
86+
87+
test('pub get respects the bound of a workspace root package', () async {
88+
final fakeFlutterRoot = d.dir('fake_flutter_root', [
89+
d.flutterVersion('1.23.0'),
90+
]);
91+
await fakeFlutterRoot.create();
92+
1793
await d.dir(appPath, [
18-
d.pubspec({
19-
'name': 'myapp',
20-
'environment': {'flutter': '>=0.5.0 <1.0.0'},
21-
}),
94+
d.appPubspec(
95+
extras: {
96+
'environment': {'sdk': '^3.9.0'},
97+
'workspace': ['app'],
98+
},
99+
),
100+
d.dir('app', [
101+
d.libPubspec(
102+
'app',
103+
'1.0.0',
104+
resolutionWorkspace: true,
105+
extras: {
106+
'environment': {'sdk': '^3.9.0', 'flutter': '>=0.5.0 <1.0.0'},
107+
},
108+
),
109+
]),
22110
]).create();
23111

24112
await pubGet(
25-
exitCode: exit_codes.SUCCESS,
26-
environment: {'FLUTTER_ROOT': fakeFlutterRoot.io.path},
113+
exitCode: 1,
114+
environment: {
115+
'_PUB_TEST_SDK_VERSION': '3.9.0',
116+
'FLUTTER_ROOT': fakeFlutterRoot.io.path,
117+
},
118+
error: contains(
119+
'Because app requires '
120+
'Flutter SDK version >=0.5.0 <1.0.0, version solving failed',
121+
),
27122
);
28123
});
29124
}

test/pubspec_test.dart

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,7 @@ dependencies:
793793
final pubspec = Pubspec.parse(
794794
'''
795795
environment:
796-
sdk: ">=1.2.3 <2.3.4"
796+
sdk: ">=3.10.3 <3.11.4"
797797
flutter: ^0.1.2
798798
fuchsia: ^5.6.7
799799
''',
@@ -804,17 +804,14 @@ environment:
804804
pubspec.sdkConstraints,
805805
containsPair(
806806
'dart',
807-
SdkConstraint(VersionConstraint.parse('>=1.2.3 <2.3.4')),
807+
SdkConstraint(VersionConstraint.parse('>=3.10.3 <3.11.4')),
808808
),
809809
);
810810
expect(
811811
pubspec.sdkConstraints,
812812
containsPair(
813813
'flutter',
814-
SdkConstraint(
815-
VersionConstraint.parse('>=0.1.2'),
816-
originalConstraint: VersionConstraint.parse('^0.1.2'),
817-
),
814+
SdkConstraint(VersionConstraint.parse('^0.1.2')),
818815
),
819816
);
820817
expect(

0 commit comments

Comments
 (0)