Don't require homepage on `pub publish` (#2313)

Also validate the repository field.
diff --git a/lib/src/validator/pubspec_field.dart b/lib/src/validator/pubspec_field.dart
index 84827fc..58b7962 100644
--- a/lib/src/validator/pubspec_field.dart
+++ b/lib/src/validator/pubspec_field.dart
@@ -15,8 +15,13 @@
   @override
   Future validate() {
     _validateFieldIsString('description');
-    _validateFieldIsString('homepage');
     _validateFieldUrl('homepage');
+    _validateFieldUrl('repository');
+    if (!_hasField('homepage') && !_hasField('repository')) {
+      warnings.add(
+          'You are strongly reccomended to add either a "homepage" or a "repository" field');
+    }
+
     _validateFieldUrl('documentation');
 
     // Any complex parsing errors in version will be exposed through
@@ -32,6 +37,8 @@
     return Future.value();
   }
 
+  bool _hasField(String field) => entrypoint.root.pubspec.fields[field] != null;
+
   /// Adds an error if [field] doesn't exist or isn't a string.
   void _validateFieldIsString(String field) {
     var value = entrypoint.root.pubspec.fields[field];
diff --git a/test/lish/force_does_not_publish_if_there_are_errors_test.dart b/test/lish/force_does_not_publish_if_there_are_errors_test.dart
index 53d388d..098c40a 100644
--- a/test/lish/force_does_not_publish_if_there_are_errors_test.dart
+++ b/test/lish/force_does_not_publish_if_there_are_errors_test.dart
@@ -15,7 +15,7 @@
 
   test('--force does not publish if there are errors', () async {
     var pkg = packageMap('test_pkg', '1.0.0');
-    pkg.remove('homepage');
+    pkg.remove('description');
     await d.dir(appPath, [d.pubspec(pkg)]).create();
 
     var server = await ShelfTestServer.create();
diff --git a/test/lish/package_validation_has_an_error_test.dart b/test/lish/package_validation_has_an_error_test.dart
index c51f315..a23bf3c 100644
--- a/test/lish/package_validation_has_an_error_test.dart
+++ b/test/lish/package_validation_has_an_error_test.dart
@@ -15,7 +15,7 @@
 
   test('package validation has an error', () async {
     var pkg = packageMap('test_pkg', '1.0.0');
-    pkg.remove('homepage');
+    pkg.remove('description');
     await d.dir(appPath, [d.pubspec(pkg)]).create();
 
     var server = await ShelfTestServer.create();
diff --git a/test/validator/pubspec_field_test.dart b/test/validator/pubspec_field_test.dart
index b17fdfe..fa6f85f 100644
--- a/test/validator/pubspec_field_test.dart
+++ b/test/validator/pubspec_field_test.dart
@@ -29,6 +29,15 @@
       expectNoValidationError(pubspecField);
     });
 
+    test('has an HTTPS repository URL instead of homepage', () async {
+      var pkg = packageMap('test_pkg', '1.0.0');
+      pkg.remove('homepage');
+      pkg['repository'] = 'https://pub.dartlang.org';
+      await d.dir(appPath, [d.pubspec(pkg)]).create();
+
+      expectNoValidationError(pubspecField);
+    });
+
     test('has an HTTPS documentation URL', () async {
       var pkg = packageMap('test_pkg', '1.0.0');
       pkg['documentation'] = 'https://pub.dartlang.org';
@@ -38,16 +47,19 @@
     });
   });
 
-  group('should consider a package invalid if it', () {
-    setUp(d.validPackage.create);
-
-    test('is missing the "homepage" field', () async {
+  group('should warn if a package', () {
+    test('is missing both the "homepage" and the "description" field',
+        () async {
       var pkg = packageMap('test_pkg', '1.0.0');
       pkg.remove('homepage');
       await d.dir(appPath, [d.pubspec(pkg)]).create();
 
-      expectValidationError(pubspecField);
+      expectValidationWarning(pubspecField);
     });
+  });
+
+  group('should consider a package invalid if it', () {
+    setUp(d.validPackage.create);
 
     test('is missing the "description" field', () async {
       var pkg = packageMap('test_pkg', '1.0.0');
@@ -65,6 +77,14 @@
       expectValidationError(pubspecField);
     });
 
+    test('has a non-string "repository" field', () async {
+      var pkg = packageMap('test_pkg', '1.0.0');
+      pkg['repository'] = 12;
+      await d.dir(appPath, [d.pubspec(pkg)]).create();
+
+      expectValidationError(pubspecField);
+    });
+
     test('has a non-string "description" field', () async {
       var pkg = packageMap('test_pkg', '1.0.0');
       pkg['description'] = 12;
@@ -88,5 +108,13 @@
 
       expectValidationError(pubspecField);
     });
+
+    test('has a non-HTTP repository URL', () async {
+      var pkg = packageMap('test_pkg', '1.0.0');
+      pkg['repository'] = 'file:///foo/bar';
+      await d.dir(appPath, [d.pubspec(pkg)]).create();
+
+      expectValidationError(pubspecField);
+    });
   });
 }