Merge changes from topic "issue-8535" into stable-3.0

* changes:
  Implement per-project plugin configuration
  Add gr-repo-plugin-config
  Add gr-plugin-config-array-editor
diff --git a/WORKSPACE b/WORKSPACE
index 2a0c1ec..8be67bc 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -14,9 +14,9 @@
 
 http_archive(
     name = "io_bazel_rules_closure",
-    sha256 = "34abd9170fdbfdfc6f3b63f2c18cee3cbcb2ddbd5e3c97324add0aa7809ed875",
-    strip_prefix = "rules_closure-9d543facf886631e4ed379996e60ce3533188adc",
-    urls = ["https://github.com/bazelbuild/rules_closure/archive/9d543facf886631e4ed379996e60ce3533188adc.tar.gz"],
+    sha256 = "1c05fea22c9630cf1047f25d008780756373a60ddd4d2a6993cf9858279c5da6",
+    strip_prefix = "rules_closure-50d3dc9e6d27a5577a0f95708466718825d579f4",
+    urls = ["https://github.com/bazelbuild/rules_closure/archive/50d3dc9e6d27a5577a0f95708466718825d579f4.tar.gz"],
 )
 
 # Transitive dependency of rules_closure and protobuf
@@ -730,14 +730,14 @@
 # Keep this version of Soy synchronized with the version used in Gitiles.
 maven_jar(
     name = "soy",
-    artifact = "com.google.template:soy:2018-03-14",
-    sha1 = "76a1322705ba5a6d6329ee26e7387417725ce4b3",
+    artifact = "com.google.template:soy:2019-03-11",
+    sha1 = "119ac4b3eb0e2c638526ca99374013965c727097",
 )
 
 maven_jar(
     name = "html-types",
-    artifact = "com.google.common.html.types:types:1.0.4",
-    sha1 = "2adf4c8bfccc0ff7346f9186ac5aa57d829ad065",
+    artifact = "com.google.common.html.types:types:1.0.8",
+    sha1 = "9e9cf7bc4b2a60efeb5f5581fe46d17c068e0777",
 )
 
 maven_jar(
diff --git a/java/com/google/gerrit/gpg/server/PostGpgKeys.java b/java/com/google/gerrit/gpg/server/PostGpgKeys.java
index 57c95a9..f641902 100644
--- a/java/com/google/gerrit/gpg/server/PostGpgKeys.java
+++ b/java/com/google/gerrit/gpg/server/PostGpgKeys.java
@@ -193,10 +193,11 @@
       throws BadRequestException, ResourceConflictException, PGPException, IOException {
     try (PublicKeyStore store = storeProvider.get()) {
       List<String> addedKeys = new ArrayList<>();
+      IdentifiedUser user = rsrc.getUser();
       for (PGPPublicKeyRing keyRing : keyRings) {
         PGPPublicKey key = keyRing.getPublicKey();
         // Don't check web of trust; admins can fill in certifications later.
-        CheckResult result = checkerFactory.create(rsrc.getUser(), store).disableTrust().check(key);
+        CheckResult result = checkerFactory.create(user, store).disableTrust().check(key);
         if (!result.isOk()) {
           throw new BadRequestException(
               String.format(
@@ -211,7 +212,7 @@
       }
       CommitBuilder cb = new CommitBuilder();
       PersonIdent committer = serverIdent.get();
-      cb.setAuthor(rsrc.getUser().newCommitterIdent(committer.getWhen(), committer.getTimeZone()));
+      cb.setAuthor(user.newCommitterIdent(committer.getWhen(), committer.getTimeZone()));
       cb.setCommitter(committer);
 
       RefUpdate.Result saveResult = store.save(cb);
@@ -219,12 +220,14 @@
         case NEW:
         case FAST_FORWARD:
         case FORCED:
-          try {
-            addKeyFactory.create(rsrc.getUser(), addedKeys).send();
-          } catch (EmailException e) {
-            logger.atSevere().withCause(e).log(
-                "Cannot send GPG key added message to %s",
-                rsrc.getUser().getAccount().getPreferredEmail());
+          if (!addedKeys.isEmpty()) {
+            try {
+              addKeyFactory.create(user, addedKeys).send();
+            } catch (EmailException e) {
+              logger.atSevere().withCause(e).log(
+                  "Cannot send GPG key added message to %s",
+                  rsrc.getUser().getAccount().getPreferredEmail());
+            }
           }
           break;
         case NO_CHANGE:
diff --git a/java/com/google/gerrit/pgm/init/SitePathInitializer.java b/java/com/google/gerrit/pgm/init/SitePathInitializer.java
index bc562cc..9d09461 100644
--- a/java/com/google/gerrit/pgm/init/SitePathInitializer.java
+++ b/java/com/google/gerrit/pgm/init/SitePathInitializer.java
@@ -107,6 +107,7 @@
     extractMailExample("Abandoned.soy");
     extractMailExample("AbandonedHtml.soy");
     extractMailExample("AddKey.soy");
+    extractMailExample("AddKeyHtml.soy");
     extractMailExample("ChangeFooter.soy");
     extractMailExample("ChangeFooterHtml.soy");
     extractMailExample("ChangeSubject.soy");
diff --git a/java/com/google/gerrit/server/config/GerritGlobalModule.java b/java/com/google/gerrit/server/config/GerritGlobalModule.java
index f168ef9..59a55ab 100644
--- a/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -140,19 +140,11 @@
 import com.google.gerrit.server.mail.EmailModule;
 import com.google.gerrit.server.mail.ListMailFilter;
 import com.google.gerrit.server.mail.MailFilter;
-import com.google.gerrit.server.mail.send.AddKeySender;
-import com.google.gerrit.server.mail.send.AddReviewerSender;
-import com.google.gerrit.server.mail.send.CreateChangeSender;
-import com.google.gerrit.server.mail.send.DeleteReviewerSender;
 import com.google.gerrit.server.mail.send.FromAddressGenerator;
 import com.google.gerrit.server.mail.send.FromAddressGeneratorProvider;
 import com.google.gerrit.server.mail.send.InboundEmailRejectionSender;
 import com.google.gerrit.server.mail.send.MailSoyTofuProvider;
 import com.google.gerrit.server.mail.send.MailTemplates;
-import com.google.gerrit.server.mail.send.MergedSender;
-import com.google.gerrit.server.mail.send.RegisterNewEmailSender;
-import com.google.gerrit.server.mail.send.ReplacePatchSetSender;
-import com.google.gerrit.server.mail.send.SetAssigneeSender;
 import com.google.gerrit.server.mime.FileTypeRegistry;
 import com.google.gerrit.server.mime.MimeUtilFileTypeRegistry;
 import com.google.gerrit.server.notedb.NoteDbModule;
@@ -255,22 +247,14 @@
     install(new SshAddressesModule());
     install(ThreadLocalRequestContext.module());
 
-    factory(AddReviewerSender.Factory.class);
-    factory(DeleteReviewerSender.Factory.class);
-    factory(AddKeySender.Factory.class);
     factory(CapabilityCollection.Factory.class);
     factory(ChangeData.AssistedFactory.class);
     factory(ChangeJson.AssistedFactory.class);
-    factory(CreateChangeSender.Factory.class);
     factory(LabelsJson.Factory.class);
-    factory(MergedSender.Factory.class);
     factory(MergeUtil.Factory.class);
     factory(PatchScriptFactory.Factory.class);
     factory(ProjectState.Factory.class);
-    factory(RegisterNewEmailSender.Factory.class);
-    factory(ReplacePatchSetSender.Factory.class);
     factory(RevisionJson.Factory.class);
-    factory(SetAssigneeSender.Factory.class);
     factory(InboundEmailRejectionSender.Factory.class);
     bind(PermissionCollection.Factory.class);
     bind(AccountVisibility.class).toProvider(AccountVisibilityProvider.class).in(SINGLETON);
diff --git a/java/com/google/gerrit/server/mail/EmailModule.java b/java/com/google/gerrit/server/mail/EmailModule.java
index 9bf97dd..862293e 100644
--- a/java/com/google/gerrit/server/mail/EmailModule.java
+++ b/java/com/google/gerrit/server/mail/EmailModule.java
@@ -16,20 +16,34 @@
 
 import com.google.gerrit.extensions.config.FactoryModule;
 import com.google.gerrit.server.mail.send.AbandonedSender;
+import com.google.gerrit.server.mail.send.AddKeySender;
+import com.google.gerrit.server.mail.send.AddReviewerSender;
 import com.google.gerrit.server.mail.send.CommentSender;
+import com.google.gerrit.server.mail.send.CreateChangeSender;
 import com.google.gerrit.server.mail.send.DeleteReviewerSender;
 import com.google.gerrit.server.mail.send.DeleteVoteSender;
+import com.google.gerrit.server.mail.send.MergedSender;
+import com.google.gerrit.server.mail.send.RegisterNewEmailSender;
+import com.google.gerrit.server.mail.send.ReplacePatchSetSender;
 import com.google.gerrit.server.mail.send.RestoredSender;
 import com.google.gerrit.server.mail.send.RevertedSender;
+import com.google.gerrit.server.mail.send.SetAssigneeSender;
 
 public class EmailModule extends FactoryModule {
   @Override
   protected void configure() {
     factory(AbandonedSender.Factory.class);
+    factory(AddKeySender.Factory.class);
+    factory(AddReviewerSender.Factory.class);
     factory(CommentSender.Factory.class);
+    factory(CreateChangeSender.Factory.class);
     factory(DeleteReviewerSender.Factory.class);
     factory(DeleteVoteSender.Factory.class);
+    factory(MergedSender.Factory.class);
+    factory(RegisterNewEmailSender.Factory.class);
+    factory(ReplacePatchSetSender.Factory.class);
     factory(RestoredSender.Factory.class);
     factory(RevertedSender.Factory.class);
+    factory(SetAssigneeSender.Factory.class);
   }
 }
diff --git a/java/com/google/gerrit/server/restapi/config/ListTopMenus.java b/java/com/google/gerrit/server/restapi/config/ListTopMenus.java
index 2feb580..01c273c 100644
--- a/java/com/google/gerrit/server/restapi/config/ListTopMenus.java
+++ b/java/com/google/gerrit/server/restapi/config/ListTopMenus.java
@@ -26,7 +26,7 @@
 import java.util.List;
 
 @Singleton
-class ListTopMenus implements RestReadView<ConfigResource> {
+public class ListTopMenus implements RestReadView<ConfigResource> {
   private final PluginSetContext<TopMenu> extensions;
 
   @Inject
diff --git a/lib/jgit/jgit.bzl b/lib/jgit/jgit.bzl
index b3b73ad..6828807 100644
--- a/lib/jgit/jgit.bzl
+++ b/lib/jgit/jgit.bzl
@@ -4,7 +4,7 @@
 
 _DOC_VERS = _JGIT_VERS  # Set to _JGIT_VERS unless using a snapshot
 
-JGIT_DOC_URL = "http://download.eclipse.org/jgit/site/" + _DOC_VERS + "/apidocs"
+JGIT_DOC_URL = "https://download.eclipse.org/jgit/site/" + _DOC_VERS + "/apidocs"
 
 _JGIT_REPO = MAVEN_CENTRAL  # Leave here even if set to MAVEN_CENTRAL.
 
diff --git a/plugins/delete-project b/plugins/delete-project
index 195458f..86baa26 160000
--- a/plugins/delete-project
+++ b/plugins/delete-project
@@ -1 +1 @@
-Subproject commit 195458f8d39ed40cc84f9730193da9571551e104
+Subproject commit 86baa2628036cfea5d067d752825af1ebbe9af6d
diff --git a/tools/bzl/javadoc.bzl b/tools/bzl/javadoc.bzl
index fcf9f33..6387210 100644
--- a/tools/bzl/javadoc.bzl
+++ b/tools/bzl/javadoc.bzl
@@ -23,7 +23,7 @@
     transitive_jar_paths = [j.path for j in transitive_jars.to_list()]
     dir = ctx.outputs.zip.path + ".dir"
     source = ctx.outputs.zip.path + ".source"
-    external_docs = ["http://docs.oracle.com/javase/8/docs/api"] + ctx.attr.external_docs
+    external_docs = ["https://docs.oracle.com/javase/8/docs/api"] + ctx.attr.external_docs
     cmd = [
         "TZ=UTC",
         "export TZ",
diff --git a/tools/js/npm_pack.py b/tools/js/npm_pack.py
index f14262a..57f3166 100755
--- a/tools/js/npm_pack.py
+++ b/tools/js/npm_pack.py
@@ -54,7 +54,7 @@
 
     name, version = args
     filename = '%s-%s.tgz' % (name, version)
-    url = 'http://registry.npmjs.org/%s/-/%s' % (name, filename)
+    url = 'https://registry.npmjs.org/%s/-/%s' % (name, filename)
 
     tmpdir = tempfile.mkdtemp()
     tgz = os.path.join(tmpdir, filename)
diff --git a/tools/util.py b/tools/util.py
index 172ecfe..947e2c0 100644
--- a/tools/util.py
+++ b/tools/util.py
@@ -16,9 +16,9 @@
 
 REPO_ROOTS = {
   'ECLIPSE': 'https://repo.eclipse.org/content/groups/releases',
-  'GERRIT': 'http://gerrit-maven.storage.googleapis.com',
+  'GERRIT': 'https://gerrit-maven.storage.googleapis.com',
   'GERRIT_API': 'https://gerrit-api.commondatastorage.googleapis.com/release',
-  'MAVEN_CENTRAL': 'http://repo1.maven.org/maven2',
+  'MAVEN_CENTRAL': 'https://repo1.maven.org/maven2',
   'MAVEN_LOCAL': 'file://' + path.expanduser('~/.m2/repository'),
   'MAVEN_SNAPSHOT': 'https://oss.sonatype.org/content/repositories/snapshots',
 }
diff --git a/tools/util_test.py b/tools/util_test.py
index fa67696..1a389f5 100644
--- a/tools/util_test.py
+++ b/tools/util_test.py
@@ -29,18 +29,18 @@
 
     def testKnownRedirect(self):
         url = resolve_url('MAVEN_CENTRAL:foo.jar',
-                          {'MAVEN_CENTRAL': 'http://my.company.mirror/maven2'})
-        self.assertEqual(url, 'http://my.company.mirror/maven2/foo.jar')
+                          {'MAVEN_CENTRAL': 'https://my.company.mirror/maven2'})
+        self.assertEqual(url, 'https://my.company.mirror/maven2/foo.jar')
 
     def testCustom(self):
-        url = resolve_url('http://maven.example.com/release/foo.jar', {})
-        self.assertEqual(url, 'http://maven.example.com/release/foo.jar')
+        url = resolve_url('https://maven.example.com/release/foo.jar', {})
+        self.assertEqual(url, 'https://maven.example.com/release/foo.jar')
 
     def testCustomRedirect(self):
         url = resolve_url('MAVEN_EXAMPLE:foo.jar',
                           {'MAVEN_EXAMPLE':
-                           'http://maven.example.com/release'})
-        self.assertEqual(url, 'http://maven.example.com/release/foo.jar')
+                           'https://maven.example.com/release'})
+        self.assertEqual(url, 'https://maven.example.com/release/foo.jar')
 
 
 if __name__ == '__main__':