Merge branch 'stable-3.1'

* stable-3.1:
  CommentsIT#postCommentsUnreachableData: Remove unnecessary setApiUser call
  ChangeDraftUpdate: Remove unused local variable
  Fix deletion of draft comment refs
  Upgrade testcontainers to 1.12.4
  Fix loading font-roboto-local in the ui
  ExternalIdCacheLoader: suppress warning if cache is not persisted.
  ChangeEmail: add project to email headers
  OutgoingEmail: use consistently va.smtpRcptTo reference
  NotificationEmail: use MailHeader for 'Gerrit-Branch' footer name
  Update git submodules
  Update git submodules
  Update git submodules
  Fix "TypeError: groups is not iterable" in _disableAgreements
  Fix typos: Aggreements -> Agreements
  Upgrade gitiles-servlet and blame-cache to 0.3-7

Change-Id: I3640f489c25eebaa024fe8b6992adc5956d71547
diff --git a/WORKSPACE b/WORKSPACE
index 7529d8a..e370f69 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -748,7 +748,7 @@
     sha1 = "f7be08ec23c21485b9b5a1cf1654c2ec8c58168d",
 )
 
-GITILES_VERS = "0.3-6"
+GITILES_VERS = "0.3-7"
 
 GITILES_REPO = GERRIT
 
@@ -757,14 +757,14 @@
     artifact = "com.google.gitiles:blame-cache:" + GITILES_VERS,
     attach_source = False,
     repository = GITILES_REPO,
-    sha1 = "bd1ec86570b8a6e4b68c5af6311c8cd10aa3f295",
+    sha1 = "af6212a62363906c63d367f8276ae1645f83bf93",
 )
 
 maven_jar(
     name = "gitiles-servlet",
     artifact = "com.google.gitiles:gitiles-servlet:" + GITILES_VERS,
     repository = GITILES_REPO,
-    sha1 = "98bf06ca9abc871beb3d6c01e6f053243d4e911a",
+    sha1 = "6a53f722f8572a2f1bcb7d86e5692168844bab76",
 )
 
 # prettify must match the version used in Gitiles
diff --git a/java/com/google/gerrit/server/mail/send/ChangeEmail.java b/java/com/google/gerrit/server/mail/send/ChangeEmail.java
index 36b3c20..d7f09d2 100644
--- a/java/com/google/gerrit/server/mail/send/ChangeEmail.java
+++ b/java/com/google/gerrit/server/mail/send/ChangeEmail.java
@@ -180,6 +180,7 @@
     setChangeSubjectHeader();
     setHeader(MailHeader.CHANGE_ID.fieldName(), "" + change.getKey().get());
     setHeader(MailHeader.CHANGE_NUMBER.fieldName(), "" + change.getChangeId());
+    setHeader(MailHeader.PROJECT.fieldName(), "" + change.getProject());
     setChangeUrlHeader();
     setCommitIdHeader();
 
diff --git a/java/com/google/gerrit/server/mail/send/NotificationEmail.java b/java/com/google/gerrit/server/mail/send/NotificationEmail.java
index f928bf0..0fb5c6f 100644
--- a/java/com/google/gerrit/server/mail/send/NotificationEmail.java
+++ b/java/com/google/gerrit/server/mail/send/NotificationEmail.java
@@ -122,7 +122,7 @@
     soyContext.put("branch", branchData);
 
     footers.add(MailHeader.PROJECT.withDelimiter() + branch.project().get());
-    footers.add("Gerrit-Branch: " + branch.shortName());
+    footers.add(MailHeader.BRANCH.withDelimiter() + branch.shortName());
   }
 
   @VisibleForTesting
diff --git a/java/com/google/gerrit/server/mail/send/OutgoingEmail.java b/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
index 7d2fa0a..e81f7f4 100644
--- a/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
+++ b/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
@@ -211,12 +211,12 @@
         }
       }
 
-      Set<Address> intersection = Sets.intersection(smtpRcptTo, smtpRcptToPlaintextOnly);
+      Set<Address> intersection = Sets.intersection(va.smtpRcptTo, smtpRcptToPlaintextOnly);
       if (!intersection.isEmpty()) {
         logger.atSevere().log("Email '%s' will be sent twice to %s", messageClass, intersection);
       }
 
-      if (!smtpRcptTo.isEmpty()) {
+      if (!va.smtpRcptTo.isEmpty()) {
         // Send multipart message
         logger.atFine().log(
             "Sending multipart '%s' from %s to %s",
diff --git a/javatests/com/google/gerrit/acceptance/server/change/CommentsIT.java b/javatests/com/google/gerrit/acceptance/server/change/CommentsIT.java
index 65f8aa0..ba41d7e 100644
--- a/javatests/com/google/gerrit/acceptance/server/change/CommentsIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/change/CommentsIT.java
@@ -319,8 +319,6 @@
 
   @Test
   public void postCommentsUnreachableData() throws Exception {
-    requestScopeOperations.setApiUser(admin.id());
-
     String file = "file";
     PushOneCommit push =
         pushFactory.create(admin.newIdent(), testRepo, "first subject", file, "l1\nl2\n");
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.html b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.html
index fb5ab15..fb5d64f 100644
--- a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.html
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.html
@@ -80,10 +80,10 @@
               data-name$="[[item.name]]"
               data-url$="[[item.url]]"
               on-click="_handleShowAgreement"
-              disabled$="[[_disableAggreements(item, _groups, _signedAgreements)]]">
+              disabled$="[[_disableAgreements(item, _groups, _signedAgreements)]]">
           <label id="claNewAgreementsLabel">[[item.name]]</label>
         </span>
-        <div class$="alreadySubmittedText [[_hideAggreements(item, _groups, _signedAgreements)]]">
+        <div class$="alreadySubmittedText [[_hideAgreements(item, _groups, _signedAgreements)]]">
           Agreement already submitted.
         </div>
         <div class="agreementsUrl">
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.js b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.js
index 98f1413..863577c 100644
--- a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.js
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.js
@@ -117,7 +117,8 @@
       return agreements ? 'show' : '';
     }
 
-    _disableAggreements(item, groups, signedAgreements) {
+    _disableAgreements(item, groups, signedAgreements) {
+      if (!groups) return false;
       for (const group of groups) {
         if ((item && item.auto_verify_group &&
             item.auto_verify_group.id === group.id) ||
@@ -128,8 +129,8 @@
       return false;
     }
 
-    _hideAggreements(item, groups, signedAgreements) {
-      return this._disableAggreements(item, groups, signedAgreements) ?
+    _hideAgreements(item, groups, signedAgreements) {
+      return this._disableAgreements(item, groups, signedAgreements) ?
         '' : 'hide';
     }
 
@@ -141,6 +142,7 @@
     // if specified it returns 'hideAgreementsTextBox' which
     // then hides the text box and submit button.
     _computeHideAgreementClass(name, config) {
+      if (!config) return '';
       for (const key in config) {
         if (!config.hasOwnProperty(key)) {
           continue;
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.html b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.html
index 833fa39..13c4de4 100644
--- a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.html
@@ -142,28 +142,31 @@
           'none');
     });
 
-    test('_disableAggreements', () => {
+    test('_disableAgreements', () => {
       // In the auto verify group and have not yet signed agreement
       assert.isTrue(
-          element._disableAggreements(auth, groups, signedAgreements));
+          element._disableAgreements(auth, groups, signedAgreements));
       // Not in the auto verify group and have not yet signed agreement
       assert.isFalse(
-          element._disableAggreements(auth2, groups, signedAgreements));
+          element._disableAgreements(auth2, groups, signedAgreements));
       // Not in the auto verify group, have signed agreement
       assert.isTrue(
-          element._disableAggreements(auth3, groups, signedAgreements));
+          element._disableAgreements(auth3, groups, signedAgreements));
+      // Make sure the undefined check works
+      assert.isFalse(
+          element._disableAgreements(auth, undefined, signedAgreements));
     });
 
-    test('_hideAggreements', () => {
+    test('_hideAgreements', () => {
       // Not in the auto verify group and have not yet signed agreement
       assert.equal(
-          element._hideAggreements(auth, groups, signedAgreements), '');
+          element._hideAgreements(auth, groups, signedAgreements), '');
       // In the auto verify group
       assert.equal(
-          element._hideAggreements(auth2, groups, signedAgreements), 'hide');
+          element._hideAgreements(auth2, groups, signedAgreements), 'hide');
       // Not in the auto verify group, have signed agreement
       assert.equal(
-          element._hideAggreements(auth3, groups, signedAgreements), '');
+          element._hideAgreements(auth3, groups, signedAgreements), '');
     });
 
     test('_disableAgreementsText', () => {
diff --git a/polygerrit-ui/app/rules.bzl b/polygerrit-ui/app/rules.bzl
index 16c0f29..e1304e6 100644
--- a/polygerrit-ui/app/rules.bzl
+++ b/polygerrit-ui/app/rules.bzl
@@ -89,6 +89,8 @@
             # we extract from the zip, but depend on the component for license checking.
             "@webcomponentsjs//:zipfile",
             "//lib/js:webcomponentsjs",
+            "@font-roboto-local//:zipfile",
+            "//lib/js:font-roboto-local",
         ],
         outs = outs,
         cmd = " && ".join([
@@ -100,6 +102,7 @@
             "for f in $(locations " + name + "_theme_sources); do cp $$f $$TMP/polygerrit_ui/styles/themes; done",
             "for f in $(locations //lib/js:highlightjs_files); do cp $$f $$TMP/polygerrit_ui/bower_components/highlightjs/ ; done",
             "unzip -qd $$TMP/polygerrit_ui/bower_components $(location @webcomponentsjs//:zipfile) webcomponentsjs/webcomponents-lite.js",
+            "unzip -qd $$TMP/polygerrit_ui/bower_components $(location @font-roboto-local//:zipfile) font-roboto-local/fonts/\*/\*.ttf",
             "cd $$TMP",
             "find . -exec touch -t 198001010000 '{}' ';'",
             "zip -qr $$ROOT/$@ *",
diff --git a/tools/nongoogle.bzl b/tools/nongoogle.bzl
index 357faa4..1dfc2f4 100644
--- a/tools/nongoogle.bzl
+++ b/tools/nongoogle.bzl
@@ -170,18 +170,18 @@
         sha1 = "3e83394258ae2089be7219b971ec21a8288528ad",
     )
 
-    TESTCONTAINERS_VERSION = "1.12.3"
+    TESTCONTAINERS_VERSION = "1.12.4"
 
     maven_jar(
         name = "testcontainers",
         artifact = "org.testcontainers:testcontainers:" + TESTCONTAINERS_VERSION,
-        sha1 = "e424a4549640e120acceac641ac909fcda58bf62",
+        sha1 = "456b6facac12c4b67130d9056a43c011679e9f0c",
     )
 
     maven_jar(
         name = "testcontainers-elasticsearch",
         artifact = "org.testcontainers:elasticsearch:" + TESTCONTAINERS_VERSION,
-        sha1 = "c0796de5032070b8768ce78c78949b48f13c30db",
+        sha1 = "9e210c277a35a95a76d03a79e2812575bd07391c",
     )
 
     maven_jar(