Warn when non-prerelease depends on pre-release SDK or package (#2356)
diff --git a/lib/src/validator/dependency.dart b/lib/src/validator/dependency.dart
index ba5da98..054fe9c 100644
--- a/lib/src/validator/dependency.dart
+++ b/lib/src/validator/dependency.dart
@@ -75,18 +75,22 @@
validateSdkConstraint(_firstGitPathVersion,
"Older versions of pub don't support Git path dependencies.");
}
- } else if (constraint.isAny) {
- _warnAboutNoConstraint(dependency);
- } else if (constraint is Version) {
- _warnAboutSingleVersionConstraint(dependency);
- } else if (constraint is VersionRange) {
- if (constraint.min == null) {
- _warnAboutNoConstraintLowerBound(dependency);
- } else if (constraint.max == null) {
- _warnAboutNoConstraintUpperBound(dependency);
+ } else {
+ if (constraint.isAny) {
+ _warnAboutNoConstraint(dependency);
+ } else if (constraint is VersionRange) {
+ if (constraint is Version) {
+ _warnAboutSingleVersionConstraint(dependency);
+ } else {
+ _warnAboutPrerelease(dependency.name, constraint);
+ if (constraint.min == null) {
+ _warnAboutNoConstraintLowerBound(dependency);
+ } else if (constraint.max == null) {
+ _warnAboutNoConstraintUpperBound(dependency);
+ }
+ }
+ _hasCaretDep = _hasCaretDep || constraint.toString().startsWith('^');
}
-
- _hasCaretDep = _hasCaretDep || constraint.toString().startsWith('^');
}
_hasFeatures = _hasFeatures || dependency.features.isNotEmpty;
@@ -231,4 +235,18 @@
'Without an upper bound, you\'re promising to support '
'${log.bold("all")} future versions of ${dep.name}.');
}
+
+ void _warnAboutPrerelease(String dependencyName, VersionRange constraint) {
+ final packageVersion = entrypoint.root.version;
+ if (constraint.min != null &&
+ constraint.min.isPreRelease &&
+ !packageVersion.isPreRelease) {
+ warnings.add('Packages dependent on a pre-release of another package '
+ 'should themselves be published as a pre-release version. '
+ 'If this package needs $dependencyName version ${constraint.min}, '
+ 'consider publishing the package as a pre-release instead.\n'
+ 'See https://dart.dev/tools/pub/publishing#publishing-prereleases '
+ 'For more information on pre-releases.');
+ }
+ }
}
diff --git a/lib/src/validator/sdk_constraint.dart b/lib/src/validator/sdk_constraint.dart
index 7465a37..7799cf0 100644
--- a/lib/src/validator/sdk_constraint.dart
+++ b/lib/src/validator/sdk_constraint.dart
@@ -10,8 +10,13 @@
import '../sdk.dart';
import '../validator.dart';
-/// A validator that validates that a package's SDK constraint doesn't use the
-/// "^" syntax.
+/// A validator of the SDK constraint.
+///
+/// Validates that a package's SDK constraint:
+/// * doesn't use the "^" syntax.
+/// * has an upper bound.
+/// * is not depending on a prerelease, unless the package itself is a
+/// prerelease.
class SdkConstraintValidator extends Validator {
SdkConstraintValidator(Entrypoint entrypoint) : super(entrypoint);
@@ -42,6 +47,21 @@
'See https://dart.dev/tools/pub/pubspec#sdk-constraints for '
'instructions on setting an sdk version constraint.');
}
+
+ final constraintMin = dartConstraint.min;
+ final packageVersion = entrypoint.root.version;
+
+ if (constraintMin != null &&
+ constraintMin.isPreRelease &&
+ !packageVersion.isPreRelease) {
+ warnings.add(
+ 'Packages with an SDK constraint on a pre-release of the Dart SDK '
+ 'should themselves be published as a pre-release version. '
+ 'If this package needs Dart version $constraintMin, consider '
+ 'publishing the package as a pre-release instead.\n'
+ 'See https://dart.dev/tools/pub/publishing#publishing-prereleases '
+ 'For more information on pre-releases.');
+ }
}
for (var sdk in sdks.values) {
diff --git a/test/validator/dependency_test.dart b/test/validator/dependency_test.dart
index 31ed937..3d93b68 100644
--- a/test/validator/dependency_test.dart
+++ b/test/validator/dependency_test.dart
@@ -73,6 +73,19 @@
expectNoValidationError(dependency);
});
+ test('with a dependency on a pre-release while being one', () async {
+ await d.dir(appPath, [
+ d.libPubspec(
+ 'test_pkg',
+ '1.0.0-dev',
+ deps: {'foo': '^1.2.3-dev'},
+ sdk: '>=1.19.0 <2.0.0',
+ )
+ ]).create();
+
+ expectNoValidationError(dependency);
+ });
+
test('has a git path dependency with an appropriate SDK constraint',
() async {
await d.dir(appPath, [
@@ -325,6 +338,18 @@
});
});
+ test('with a dependency on a pre-release without being one', () async {
+ await d.dir(appPath, [
+ d.libPubspec(
+ 'test_pkg',
+ '1.0.0',
+ deps: {'foo': '^1.2.3-dev'},
+ sdk: '>=1.19.0 <2.0.0',
+ )
+ ]).create();
+
+ expectDependencyValidationWarning('Packages dependent on a pre-release');
+ });
test(
'with a single-version dependency and it should suggest a '
'constraint based on the version', () async {
diff --git a/test/validator/sdk_constraint_test.dart b/test/validator/sdk_constraint_test.dart
index 554df49..d610bb8 100644
--- a/test/validator/sdk_constraint_test.dart
+++ b/test/validator/sdk_constraint_test.dart
@@ -28,6 +28,13 @@
expectNoValidationError(sdkConstraint);
});
+ test('depends on a pre-release Dart SDK from a pre-release', () async {
+ await d.dir(appPath, [
+ d.libPubspec('test_pkg', '1.0.0-dev.1', sdk: '>=1.8.0-dev.1 <2.0.0')
+ ]).create();
+ expectNoValidationError(sdkConstraint);
+ });
+
test(
'has a Flutter SDK constraint with an appropriate Dart SDK '
'constraint', () async {
@@ -47,7 +54,7 @@
await d.dir(appPath, [
d.pubspec({
'name': 'test_pkg',
- 'version': '1.0.0',
+ 'version': '1.0.0-dev.1',
'environment': {'sdk': '>=2.0.0-dev.51.0 <2.0.0', 'fuchsia': '^1.2.3'}
})
]).create();
@@ -120,7 +127,7 @@
await d.dir(appPath, [
d.pubspec({
'name': 'test_pkg',
- 'version': '1.0.0',
+ 'version': '1.0.0-dev.1',
'environment': {'sdk': '>=2.0.0-dev.50.0 <2.0.0', 'fuchsia': '^1.2.3'}
})
]).create();
@@ -143,5 +150,21 @@
completion(
pairOf(anyElement(contains('">=2.0.0 <3.0.0"')), isEmpty)));
});
+
+ test('depends on a pre-release sdk from a non-pre-release', () async {
+ await d.dir(appPath, [
+ d.libPubspec('test_pkg', '1.0.0', sdk: '>=1.8.0-dev.1 <2.0.0')
+ ]).create();
+ expect(
+ validatePackage(sdkConstraint),
+ completion(
+ pairOf(
+ isEmpty,
+ anyElement(contains(
+ 'consider publishing the package as a pre-release instead')),
+ ),
+ ),
+ );
+ });
});
}