Merge "Add enabledExperiments to soy template"
diff --git a/Documentation/user-upload.txt b/Documentation/user-upload.txt
index 86719d2..926aa71 100644
--- a/Documentation/user-upload.txt
+++ b/Documentation/user-upload.txt
@@ -580,9 +580,10 @@
 === Selecting Merge Base
 
 By default new changes are opened only for new unique commits
-that have never before been seen by the Gerrit server. Clients
-may override that behavior and force new changes to be created
-by setting the merge base SHA-1 using the '%base' argument:
+that are not part of any branch in refs/heads or the target
+branch. Clients may override that behavior and force new
+changes to be created by setting the merge base SHA-1 using
+the '%base' argument:
 
 ----
   git push ssh://john.doe@git.example.com:29418/kernel/common HEAD:refs/for/master%base=$(git rev-parse origin/master)
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
index 50aaa27..fd681d8 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -3238,13 +3238,33 @@
 
     assertThat(changeInfo.revisions.get(changeInfo.currentRevision).commit.message)
         .contains(subject);
+  }
 
-    // No subject: reuse message from previous patchset.
+  @Test
+  public void createMergePatchSet_SubjectCarriesOverByDefault() throws Exception {
+    RevCommit initialHead = projectOperations.project(project).getHead("master");
+    createBranch("dev");
+
+    // create a change for master
+    PushOneCommit.Result result = createChange();
+    String changeId = result.getChangeId();
+    String subject = result.getChange().change().getSubject();
+
+    // push a commit into dev branch
+    testRepo.reset(initialHead);
+    PushOneCommit.Result pushResult =
+        pushFactory.create(user.newIdent(), testRepo).to("refs/heads/dev");
+    pushResult.assertOkStatus();
+    MergeInput mergeInput = new MergeInput();
+    mergeInput.source = "dev";
+    MergePatchSetInput in = new MergePatchSetInput();
+    in.merge = mergeInput;
     in.subject = null;
+
+    // Ensure subject carries over
     gApi.changes().id(changeId).createMergePatchSet(in);
-    changeInfo = gApi.changes().id(changeId).get(ALL_REVISIONS, CURRENT_COMMIT, CURRENT_REVISION);
-    assertThat(changeInfo.revisions.get(changeInfo.currentRevision).commit.message)
-        .contains(subject);
+    ChangeInfo changeInfo = gApi.changes().id(changeId).get();
+    assertThat(changeInfo.subject).isEqualTo(subject);
   }
 
   @Test
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.js
index 037d53d..1daab4c 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.js
@@ -50,12 +50,9 @@
 
   static get properties() {
     return {
-    /**
-     * @type {{
-     *    is_private: boolean,
-     *    subject: string,
-     *  }}
-     */
+      /**
+       * @type {Gerrit.Change}
+       */
       change: Object,
 
       /**
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard-behavior.js b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard-behavior.js
index 1ba3c23..7828e32 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard-behavior.js
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard-behavior.js
@@ -194,16 +194,6 @@
     if (!this._isShowing) {
       return;
     }
-    const targetRect = this._target.getBoundingClientRect();
-    const x = e.clientX;
-    const y = e.clientY;
-    if (x > targetRect.left && x < targetRect.right && y > targetRect.top &&
-        y < targetRect.bottom) {
-      // Sometimes the hovercard itself obscures the mouse pointer, and
-      // that generates a mouseleave event. We don't want to hide the hovercard
-      // in that situation.
-      return;
-    }
 
     // If the user is now hovering over the hovercard or the user is returning
     // from the hovercard but now hovering over the target (to stop an annoying
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard_test.html b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard_test.html
index 99791e7..7280eb2 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard_test.html
@@ -128,15 +128,39 @@
   test('card is scheduled to show on enter and hides on leave', done => {
     const button = dom(document).querySelector('button');
     assert.isFalse(element._isShowing);
-    button.addEventListener('mouseenter', event => {
+    const enterHandler = event => {
       assert.isTrue(element._isScheduledToShow);
       button.dispatchEvent(new CustomEvent('mouseleave'));
-    });
-    button.addEventListener('mouseleave', event => {
+    };
+    const leaveHandler = event => {
       assert.isFalse(element._isScheduledToShow);
       assert.isFalse(element._isShowing);
+      button.removeEventListener('mouseenter', enterHandler);
+      button.removeEventListener('mouseleave', leaveHandler);
       done();
-    });
+    };
+    button.addEventListener('mouseenter', enterHandler);
+    button.addEventListener('mouseleave', leaveHandler);
+    button.dispatchEvent(new CustomEvent('mouseenter'));
+  });
+
+  test('card should disappear on click', done => {
+    const button = dom(document).querySelector('button');
+    assert.isFalse(element._isShowing);
+    const enterHandler = event => {
+      assert.isTrue(element._isScheduledToShow);
+      // click to hide
+      MockInteractions.tap(button);
+    };
+    const leaveHandler = event => {
+      assert.isFalse(element._isScheduledToShow);
+      assert.isFalse(element._isShowing);
+      button.removeEventListener('mouseenter', enterHandler);
+      button.removeEventListener('click', leaveHandler);
+      done();
+    };
+    button.addEventListener('mouseenter', enterHandler);
+    button.addEventListener('click', leaveHandler);
     button.dispatchEvent(new CustomEvent('mouseenter'));
   });
 });
diff --git a/polygerrit-ui/app/types/types.js b/polygerrit-ui/app/types/types.js
index 7c42d76..583c2b3 100644
--- a/polygerrit-ui/app/types/types.js
+++ b/polygerrit-ui/app/types/types.js
@@ -87,6 +87,15 @@
 Gerrit.ChangeFetchRequest;
 
 /**
+ * @typedef {{
+ *   is_private: boolean,
+ *   subject: string,
+ *   unresolved_comment_count: number,
+ * }}
+ */
+Gerrit.Change;
+
+/**
  * Object to describe a request for passing into _send.
  * - method is the HTTP method to use in the request.
  * - url is the URL for the request
diff --git a/tools/node_tools/BUILD b/tools/node_tools/BUILD
index 018674c..4019542 100644
--- a/tools/node_tools/BUILD
+++ b/tools/node_tools/BUILD
@@ -8,8 +8,12 @@
 # Usage: rollup_bundle(rollup_bin = "//tools/node_tools:rollup-bin, ...)
 nodejs_binary(
     name = "rollup-bin",
+    # Define only minimal required dependencies.
+    # Otherwise remote build execution fails with the too many
+    # files error when it builds :release target.
     data = [
-        "@tools_npm//:node_modules",
+        "@tools_npm//rollup",
+        "@tools_npm//rollup-plugin-terser",
     ],
     # The entry point must be "@tools_npm:node_modules/rollup/dist/bin/rollup",
     # But bazel doesn't run it correctly with the following command line: