Warn about deprecated LICENSE and README.md file names (#2381)
diff --git a/lib/src/validator/license.dart b/lib/src/validator/license.dart
index 4f012fc..1646b11 100644
--- a/lib/src/validator/license.dart
+++ b/lib/src/validator/license.dart
@@ -16,17 +16,22 @@
@override
Future validate() {
return Future.sync(() {
- var licenseLike =
+ final licenseLike =
RegExp(r'^(([a-zA-Z0-9]+[-_])?(LICENSE|COPYING)|UNLICENSE)(\..*)?$');
- if (entrypoint.root
+ final candidates = entrypoint.root
.listFiles(recursive: false, useGitIgnore: true)
.map(path.basename)
- .any(licenseLike.hasMatch)) {
+ .where(licenseLike.hasMatch);
+ if (candidates.isNotEmpty) {
+ if (!candidates.contains('LICENSE')) {
+ final firstCandidate = candidates.first;
+ warnings.add('Please consider renaming $firstCandidate to `LICENSE`. '
+ 'See https://dart.dev/tools/pub/publishing#important-files.');
+ }
return;
}
- errors.add(
- 'You must have a COPYING, LICENSE or UNLICENSE file in the root directory.\n'
+ errors.add('You must have a LICENSE file in the root directory.\n'
'An open-source license helps ensure people can legally use your '
'code.');
});
diff --git a/lib/src/validator/readme.dart b/lib/src/validator/readme.dart
index 716df0d..85de479 100644
--- a/lib/src/validator/readme.dart
+++ b/lib/src/validator/readme.dart
@@ -5,6 +5,8 @@
import 'dart:async';
import 'dart:convert';
+import 'package:path/path.dart' as path;
+
import '../entrypoint.dart';
import '../io.dart';
import '../validator.dart';
@@ -23,6 +25,11 @@
return;
}
+ if (path.basename(readme) != 'README.md') {
+ warnings.add('Please consider renaming $readme to `README.md`. '
+ 'See https://dart.dev/tools/pub/publishing#important-files.');
+ }
+
var bytes = readBinaryFile(readme);
try {
// utf8.decode doesn't allow invalid UTF-8.
diff --git a/test/validator/license_test.dart b/test/validator/license_test.dart
index 33726cb..eb77ef4 100644
--- a/test/validator/license_test.dart
+++ b/test/validator/license_test.dart
@@ -18,32 +18,45 @@
void main() {
group('should consider a package valid if it', () {
- setUp(d.validPackage.create);
-
- test('looks normal', () => expectNoValidationError(license));
-
- test('has a COPYING file', () async {
- deleteEntry(path.join(d.sandbox, appPath, 'LICENSE'));
- await d.file(path.join(appPath, 'COPYING'), '').create();
+ test('looks normal', () async {
+ await d.validPackage.create();
expectNoValidationError(license);
});
- test('has an UNLICENSE file', () async {
- deleteEntry(path.join(d.sandbox, appPath, 'LICENSE'));
+ test('has both LICENSE and UNLICENSE file', () async {
+ await d.validPackage.create();
await d.file(path.join(appPath, 'UNLICENSE'), '').create();
expectNoValidationError(license);
});
+ });
- test('has a prefixed LICENSE file', () async {
+ group('should warn if it', () {
+ test('has only a COPYING file', () async {
+ await d.validPackage.create();
deleteEntry(path.join(d.sandbox, appPath, 'LICENSE'));
- await d.file(path.join(appPath, 'MIT_LICENSE'), '').create();
- expectNoValidationError(license);
+ await d.file(path.join(appPath, 'COPYING'), '').create();
+ expectValidationWarning(license);
});
- test('has a suffixed LICENSE file', () async {
+ test('has only an UNLICENSE file', () async {
+ await d.validPackage.create();
+ deleteEntry(path.join(d.sandbox, appPath, 'LICENSE'));
+ await d.file(path.join(appPath, 'UNLICENSE'), '').create();
+ expectValidationWarning(license);
+ });
+
+ test('has only a prefixed LICENSE file', () async {
+ await d.validPackage.create();
+ deleteEntry(path.join(d.sandbox, appPath, 'LICENSE'));
+ await d.file(path.join(appPath, 'MIT_LICENSE'), '').create();
+ expectValidationWarning(license);
+ });
+
+ test('has only a suffixed LICENSE file', () async {
+ await d.validPackage.create();
deleteEntry(path.join(d.sandbox, appPath, 'LICENSE'));
await d.file(path.join(appPath, 'LICENSE.md'), '').create();
- expectNoValidationError(license);
+ expectValidationWarning(license);
});
});
diff --git a/test/validator/readme_test.dart b/test/validator/readme_test.dart
index 7eeb834..7a45278 100644
--- a/test/validator/readme_test.dart
+++ b/test/validator/readme_test.dart
@@ -20,16 +20,13 @@
setUp(d.validPackage.create);
group('should consider a package valid if it', () {
- test('looks normal', () => expectNoValidationError(readme));
-
- test('has a non-primary readme', () async {
- deleteEntry(p.join(d.sandbox, 'myapp/README.md'));
-
- await d.dir(appPath, [d.file('README.whatever')]).create();
+ test('looks normal', () async {
+ await d.validPackage.create();
expectNoValidationError(readme);
});
test('has a non-primary readme with invalid utf-8', () async {
+ await d.validPackage.create();
await d.dir(appPath, [
d.file('README.x.y.z', [192])
]).create();
@@ -37,6 +34,7 @@
});
test('has a gitignored README with invalid utf-8', () async {
+ await d.validPackage.create();
var repo = d.git(appPath, [
d.file('README', [192]),
d.file('.gitignore', 'README')
@@ -47,21 +45,46 @@
});
group('should consider a package invalid if it', () {
- test('has no README', () {
+ test('has no README', () async {
+ await d.validPackage.create();
+
deleteEntry(p.join(d.sandbox, 'myapp/README.md'));
expectValidationWarning(readme);
});
test('has only a .gitignored README', () async {
+ await d.validPackage.create();
await d.git(appPath, [d.file('.gitignore', 'README.md')]).create();
expectValidationWarning(readme);
});
test('has a primary README with invalid utf-8', () async {
+ await d.validPackage.create();
await d.dir(appPath, [
d.file('README', [192])
]).create();
expectValidationWarning(readme);
});
+
+ test('has only a non-primary readme', () async {
+ await d.validPackage.create();
+ deleteEntry(p.join(d.sandbox, 'myapp/README.md'));
+ await d.dir(appPath, [d.file('README.whatever')]).create();
+ expectValidationWarning(readme);
+ });
+
+ test('Uses only deprecated readme name .markdown', () async {
+ await d.validPackage.create();
+ deleteEntry(p.join(d.sandbox, 'myapp/README.md'));
+ await d.dir(appPath, [d.file('README.markdown')]).create();
+ expectValidationWarning(readme);
+ });
+
+ test('Uses only deprecated readme name .mdown', () async {
+ await d.validPackage.create();
+ deleteEntry(p.join(d.sandbox, 'myapp/README.md'));
+ await d.dir(appPath, [d.file('README.mdown')]).create();
+ expectValidationWarning(readme);
+ });
});
}