Merge changes from topic 'max-pages'

* changes:
  IndexConfig: Add maxPages option
  IndexConfig: Configure maxLimit from Config
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractSubmoduleSubscription.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractSubmoduleSubscription.java
new file mode 100644
index 0000000..8bf4511
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractSubmoduleSubscription.java
@@ -0,0 +1,82 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance.git;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.common.data.Permission;
+import com.google.gerrit.reviewdb.client.Project;
+
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevTree;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.RefSpec;
+
+public abstract class AbstractSubmoduleSubscription extends AbstractDaemonTest {
+  protected TestRepository<?> createProjectWithPush(String name)
+      throws Exception {
+    Project.NameKey project = createProject(name);
+    grant(Permission.PUSH, project, "refs/heads/*");
+    grant(Permission.SUBMIT, project, "refs/for/refs/heads/*");
+    return cloneProject(project);
+  }
+
+  protected void createSubscription(
+      TestRepository<?> repo, String branch, String subscribeToRepo,
+      String subscribeToBranch) throws Exception {
+    subscribeToRepo = name(subscribeToRepo);
+
+    // The submodule subscription module checks for gerrit.canonicalWebUrl to
+    // detect if it's configured for automatic updates. It doesn't matter if
+    // it serves from that URL.
+    String url = cfg.getString("gerrit", null, "canonicalWebUrl") + "/"
+        + subscribeToRepo;
+
+    Config cfg = new Config();
+    cfg.setString("submodule", subscribeToRepo, "path", subscribeToRepo);
+    cfg.setString("submodule", subscribeToRepo, "url", url);
+    cfg.setString("submodule", subscribeToRepo, "branch", subscribeToBranch);
+
+    repo.branch("HEAD").commit().insertChangeId()
+      .message("subject: adding new subscription")
+      .add(".gitmodules", cfg.toText().toString())
+      .create();
+
+    repo.git().push().setRemote("origin").setRefSpecs(
+        new RefSpec("HEAD:refs/heads/" + branch)).call();
+  }
+
+  protected void expectToHaveSubmoduleState(TestRepository<?> repo,
+      String branch, String submodule, ObjectId expectedId) throws Exception {
+
+    submodule = name(submodule);
+    ObjectId commitId = repo.git().fetch().setRemote("origin").call()
+        .getAdvertisedRef("refs/heads/" + branch).getObjectId();
+
+    RevWalk rw = repo.getRevWalk();
+    RevCommit c = rw.parseCommit(commitId);
+    rw.parseBody(c.getTree());
+
+    RevTree tree = c.getTree();
+    RevObject actualId = repo.get(tree, submodule);
+
+    assertThat(actualId).isEqualTo(expectedId);
+  }
+}
\ No newline at end of file
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/BUCK
index 33a3685..446a183 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/BUCK
@@ -5,9 +5,11 @@
     'DraftChangeBlockedIT.java',
     'ForcePushIT.java',
     'SubmitOnPushIT.java',
+    'SubmoduleSubscriptionsWholeTopicMergeIT.java',
     'SubmoduleSubscriptionsIT.java',
     'VisibleRefFilterIT.java',
   ],
+  deps = [':submodule_util'],
   labels = ['git'],
 )
 
@@ -22,3 +24,9 @@
   srcs = ['AbstractPushForReview.java'],
   deps = ['//gerrit-acceptance-tests:lib'],
 )
+
+java_library(
+  name = 'submodule_util',
+  srcs = ['AbstractSubmoduleSubscription.java',],
+  deps = ['//gerrit-acceptance-tests:lib',]
+)
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsIT.java
index 6d677d6..d444308 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsIT.java
@@ -16,15 +16,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.common.data.Permission;
-import com.google.gerrit.reviewdb.client.Project;
-
 import org.eclipse.jgit.junit.TestRepository;
-import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevObject;
 import org.eclipse.jgit.revwalk.RevTree;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.transport.RefSpec;
@@ -32,7 +26,7 @@
 
 import java.util.concurrent.atomic.AtomicInteger;
 
-public class SubmoduleSubscriptionsIT extends AbstractDaemonTest {
+public class SubmoduleSubscriptionsIT extends AbstractSubmoduleSubscription {
 
   @Test
   public void testSubscriptionToEmptyRepo() throws Exception {
@@ -109,14 +103,6 @@
     assertThat(hasSubmodule(subRepo, "master", "super-project")).isFalse();
   }
 
-  private TestRepository<?> createProjectWithPush(String name)
-      throws Exception {
-    Project.NameKey project = createProject(name);
-    grant(Permission.PUSH, project, "refs/heads/*");
-    grant(Permission.SUBMIT, project, "refs/for/refs/heads/*");
-    return cloneProject(project);
-  }
-
   private static AtomicInteger contentCounter = new AtomicInteger(0);
 
   private ObjectId pushChangeTo(TestRepository<?> repo, String branch, String message)
@@ -138,27 +124,6 @@
     return pushChangeTo(repo, branch, "some change");
   }
 
-  private void createSubscription(
-      TestRepository<?> repo, String branch, String subscribeToRepo,
-      String subscribeToBranch) throws Exception {
-    subscribeToRepo = name(subscribeToRepo);
-
-    // The submodule subscription module checks for gerrit.canonicalWebUrl to
-    // detect if it's configured for automatic updates. It doesn't matter if
-    // it serves from that URL.
-    String url = cfg.getString("gerrit", null, "canonicalWebUrl") + "/"
-        + subscribeToRepo;
-    String content = buildSubmoduleSection(subscribeToRepo, subscribeToRepo,
-        url, subscribeToBranch);
-    repo.branch("HEAD").commit().insertChangeId()
-      .message("subject: adding new subscription")
-      .add(".gitmodules", content)
-      .create();
-
-    repo.git().push().setRemote("origin").setRefSpecs(
-        new RefSpec("HEAD:refs/heads/" + branch)).call();
-  }
-
   private void deleteAllSubscriptions(TestRepository<?> repo, String branch)
       throws Exception {
     repo.git().fetch().setRemote("origin").call();
@@ -176,23 +141,6 @@
     assertThat(actualId).isEqualTo(expectedId);
   }
 
-  private void expectToHaveSubmoduleState(TestRepository<?> repo, String branch,
-      String submodule, ObjectId expectedId) throws Exception {
-
-    submodule = name(submodule);
-    ObjectId commitId = repo.git().fetch().setRemote("origin").call()
-        .getAdvertisedRef("refs/heads/" + branch).getObjectId();
-
-    RevWalk rw = repo.getRevWalk();
-    RevCommit c = rw.parseCommit(commitId);
-    rw.parseBody(c.getTree());
-
-    RevTree tree = c.getTree();
-    RevObject actualId = repo.get(tree, submodule);
-
-    assertThat(actualId).isEqualTo(expectedId);
-  }
-
   private boolean hasSubmodule(TestRepository<?> repo, String branch,
       String submodule) throws Exception {
 
@@ -212,12 +160,4 @@
     }
   }
 
-  private static String buildSubmoduleSection(String name,
-      String path, String url, String branch) {
-    Config cfg = new Config();
-    cfg.setString("submodule", name, "path", path);
-    cfg.setString("submodule", name, "url", url);
-    cfg.setString("submodule", name, "branch", branch);
-    return cfg.toText().toString();
-  }
 }
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
new file mode 100644
index 0000000..85037f1
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
@@ -0,0 +1,94 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance.git;
+
+import static com.google.gerrit.acceptance.GitUtil.getChangeId;
+
+import com.google.gerrit.acceptance.git.AbstractSubmoduleSubscription;
+import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.testutil.ConfigSuite;
+
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.transport.RefSpec;
+import org.junit.Test;
+
+@NoHttpd
+public class SubmoduleSubscriptionsWholeTopicMergeIT
+  extends AbstractSubmoduleSubscription {
+
+  @ConfigSuite.Default
+  public static Config submitWholeTopicEnabled() {
+    return submitWholeTopicEnabledConfig();
+  }
+
+  @Test
+  public void testSubscriptionUpdateOfManyChanges() throws Exception {
+    TestRepository<?> superRepo = createProjectWithPush("super-project");
+    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
+    createSubscription(superRepo, "master", "subscribed-to-project", "master");
+
+    ObjectId subHEAD = subRepo.branch("HEAD").commit().insertChangeId()
+        .message("some change")
+        .add("a.txt", "a contents ")
+        .create();
+    subRepo.git().push().setRemote("origin").setRefSpecs(
+          new RefSpec("HEAD:refs/heads/master")).call();
+
+    RevCommit c = subRepo.getRevWalk().parseCommit(subHEAD);
+
+    RevCommit c1 = subRepo.branch("HEAD").commit().insertChangeId()
+      .message("first change")
+      .add("asdf", "asdf\n")
+      .parent(c)
+      .create();
+    subRepo.git().push().setRemote("origin")
+      .setRefSpecs(new RefSpec("HEAD:refs/for/master/" + name("topic-foo")))
+      .call();
+
+    subRepo.reset(c.getId());
+    RevCommit c2 = subRepo.branch("HEAD").commit().insertChangeId()
+      .message("qwerty")
+      .add("qwerty", "qwerty")
+      .parent(c)
+      .create();
+
+    RevCommit c3 = subRepo.branch("HEAD").commit().insertChangeId()
+      .message("qwerty followup")
+      .add("qwerty", "qwerty\nqwerty\n")
+      .parent(c2)
+      .create();
+    subRepo.git().push().setRemote("origin")
+      .setRefSpecs(new RefSpec("HEAD:refs/for/master/" + name("topic-foo")))
+      .call();
+
+    String id1 = getChangeId(subRepo, c1).get();
+    String id2 = getChangeId(subRepo, c2).get();
+    String id3 = getChangeId(subRepo, c3).get();
+    gApi.changes().id(id1).current().review(ReviewInput.approve());
+    gApi.changes().id(id2).current().review(ReviewInput.approve());
+    gApi.changes().id(id3).current().review(ReviewInput.approve());
+
+    gApi.changes().id(id1).current().submit();
+    ObjectId subRepoId = subRepo.git().fetch().setRemote("origin").call()
+        .getAdvertisedRef("refs/heads/master").getObjectId();
+
+    expectToHaveSubmoduleState(superRepo, "master",
+        "subscribed-to-project", subRepoId);
+  }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ActionsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ActionsIT.java
index ae5a847..b53d193 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ActionsIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ActionsIT.java
@@ -18,9 +18,13 @@
 
 import com.google.gerrit.acceptance.AbstractDaemonTest;
 import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.client.SubmitType;
 import com.google.gerrit.extensions.common.ActionInfo;
 import com.google.gerrit.testutil.ConfigSuite;
 
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.lib.Config;
 import org.junit.Test;
 
@@ -34,7 +38,7 @@
 
   @Test
   public void revisionActionsOneChangePerTopicUnapproved() throws Exception {
-    String changeId = createChangeWithTopic(name("foo1")).getChangeId();
+    String changeId = createChangeWithTopic().getChangeId();
     Map<String, ActionInfo> actions = getActions(changeId);
     assertThat(actions).containsKey("cherrypick");
     assertThat(actions).containsKey("rebase");
@@ -43,7 +47,7 @@
 
   @Test
   public void revisionActionsOneChangePerTopic() throws Exception {
-    String changeId = createChangeWithTopic(name("foo1")).getChangeId();
+    String changeId = createChangeWithTopic().getChangeId();
     approve(changeId);
     Map<String, ActionInfo> actions = getActions(changeId);
     commonActionsAssertions(actions);
@@ -54,10 +58,10 @@
 
   @Test
   public void revisionActionsTwoChangeChangesInTopic() throws Exception {
-    String changeId = createChangeWithTopic(name("foo2")).getChangeId();
+    String changeId = createChangeWithTopic().getChangeId();
     approve(changeId);
     // create another change with the same topic
-    createChangeWithTopic(name("foo2")).getChangeId();
+    createChangeWithTopic().getChangeId();
     Map<String, ActionInfo> actions = getActions(changeId);
     commonActionsAssertions(actions);
     if (isSubmitWholeTopicEnabled()) {
@@ -72,11 +76,42 @@
   }
 
   @Test
+  public void revisionActionsTwoChangeChangesInTopic_conflicting() throws Exception {
+    String changeId = createChangeWithTopic().getChangeId();
+    approve(changeId);
+
+    // create another change with the same topic
+    String changeId2 = createChangeWithTopic(testRepo, "foo2", "touching b",
+        "b.txt", "real content").getChangeId();
+    approve(changeId2);
+
+    // collide with the other change in the same topic
+    testRepo.reset("HEAD~2");
+    String collidingChange = createChangeWithTopic(testRepo, "off_topic",
+        "rewriting file b", "b.txt", "garbage\ngarbage\ngarbage").getChangeId();
+    gApi.changes().id(collidingChange).current().review(ReviewInput.approve());
+    gApi.changes().id(collidingChange).current().submit();
+
+    Map<String, ActionInfo> actions = getActions(changeId);
+    commonActionsAssertions(actions);
+    if (isSubmitWholeTopicEnabled()) {
+      ActionInfo info = actions.get("submit");
+      assertThat(info.enabled).isNull();
+      assertThat(info.label).isEqualTo("Submit whole topic");
+      assertThat(info.method).isEqualTo("POST");
+      assertThat(info.title).isEqualTo(
+          "Clicking the button would fail for other changes in the topic");
+    } else {
+      noSubmitWholeTopicAssertions(actions);
+    }
+  }
+
+  @Test
   public void revisionActionsTwoChangeChangesInTopicReady() throws Exception {
-    String changeId = createChangeWithTopic(name("foo2")).getChangeId();
+    String changeId = createChangeWithTopic().getChangeId();
     approve(changeId);
     // create another change with the same topic
-    String changeId2 = createChangeWithTopic(name("foo2")).getChangeId();
+    String changeId2 = createChangeWithTopic().getChangeId();
     approve(changeId2);
     Map<String, ActionInfo> actions = getActions(changeId);
     commonActionsAssertions(actions);
@@ -106,10 +141,18 @@
     assertThat(actions).containsKey("rebase");
   }
 
-  private PushOneCommit.Result createChangeWithTopic(String topic)
-      throws Exception {
-    PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo);
+  private PushOneCommit.Result createChangeWithTopic(
+      TestRepository<InMemoryRepository> repo, String topic,
+      String commitMsg, String fileName, String content) throws Exception {
+    PushOneCommit push = pushFactory.create(db, admin.getIdent(),
+        repo, commitMsg, fileName, content);
     assertThat(topic).isNotEmpty();
-    return push.to("refs/for/master/" + topic);
+    return push.to("refs/for/master/" + name(topic));
+  }
+
+  private PushOneCommit.Result createChangeWithTopic()
+      throws Exception {
+    return createChangeWithTopic(testRepo, "foo2",
+        "a message", "a.txt", "content\n");
   }
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java
index 507a49a..84936ec 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java
@@ -332,7 +332,7 @@
           c.set_revision_number(currentRevision._number());
           c.set_branch(i.branch());
           c.set_project(i.project());
-          c.set_submittable(i.submittable());
+          c.set_submittable(i.submittable() && i.mergeable());
           arr.push(c);
         }
       }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java
index 306b515..3cba4be 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java
@@ -35,7 +35,6 @@
 import com.google.gerrit.extensions.common.ChangeInfo;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
-import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
 import com.google.gerrit.extensions.webui.UiAction;
@@ -100,6 +99,8 @@
       "Other changes in this topic are not ready";
   private static final String BLOCKED_HIDDEN_TOPIC_TOOLTIP =
       "Other hidden changes in this topic are not ready";
+  private static final String CLICK_FAILURE_OTHER_TOOLTIP =
+      "Clicking the button would fail for other changes in the topic";
 
   public enum Status {
     SUBMITTED, MERGED
@@ -134,7 +135,6 @@
   private final ParameterizedString submitTopicTooltip;
   private final boolean submitWholeTopic;
   private final Provider<InternalChangeQuery> queryProvider;
-  private final Provider<Mergeable> mergeableProvider;
 
   @Inject
   Submit(@GerritPersonIdent PersonIdent serverIdent,
@@ -151,8 +151,7 @@
       ChangeIndexer indexer,
       LabelNormalizer labelNormalizer,
       @GerritServerConfig Config cfg,
-      Provider<InternalChangeQuery> queryProvider,
-      Provider<Mergeable> mergeableProvider) {
+      Provider<InternalChangeQuery> queryProvider) {
     this.serverIdent = serverIdent;
     this.dbProvider = dbProvider;
     this.repoManager = repoManager;
@@ -180,7 +179,6 @@
         cfg.getString("change", null, "submitTopicTooltip"),
         DEFAULT_TOPIC_TOOLTIP));
     this.queryProvider = queryProvider;
-    this.mergeableProvider = mergeableProvider;
   }
 
   @Override
@@ -245,14 +243,15 @@
   }
 
   /**
-   * @param changes list of changes to be submitted at once
+   * @param changeList list of changes to be submitted at once
    * @param identifiedUser the user who is checking to submit
    * @return a reason why any of the changes is not submittable or null
    */
-  private String problemsForSubmittingChanges(List<ChangeData> changes,
+  private String problemsForSubmittingChanges(
+      List<ChangeData> changeList,
       IdentifiedUser identifiedUser) {
-    for (ChangeData c : changes) {
-      try {
+    try {
+      for (ChangeData c : changeList) {
         ChangeControl changeControl = c.changeControl().forUser(
             identifiedUser);
         if (!changeControl.isVisible(dbProvider.get())) {
@@ -261,13 +260,16 @@
         if (!changeControl.canSubmit()) {
           return BLOCKED_TOPIC_TOOLTIP;
         }
+        if (!c.isMergeable()) {
+          return CLICK_FAILURE_OTHER_TOOLTIP;
+        }
         checkSubmitRule(c, c.currentPatchSet(), false);
-      } catch (OrmException e) {
-        log.error("Error checking if change is submittable", e);
-        throw new OrmRuntimeException(e);
-      } catch (ResourceConflictException e) {
-        return BLOCKED_TOPIC_TOOLTIP;
       }
+    } catch (ResourceConflictException e) {
+      return BLOCKED_TOPIC_TOOLTIP;
+    } catch (OrmException e) {
+      log.error("Error checking if change is submittable", e);
+      throw new OrmRuntimeException("Could not determine problems for the change", e);
     }
     return null;
   }
@@ -280,12 +282,16 @@
         && resource.getChange().getStatus().isOpen()
         && resource.getPatchSet().getId().equals(current)
         && resource.getControl().canSubmit();
-
     ReviewDb db = dbProvider.get();
     ChangeData cd = changeDataFactory.create(db, resource.getControl());
-    if (problemsForSubmittingChanges(Arrays.asList(cd), resource.getUser())
-        != null) {
+
+    try {
+      checkSubmitRule(cd, cd.currentPatchSet(), false);
+    } catch (ResourceConflictException e) {
       visible = false;
+    } catch (OrmException e) {
+      log.error("Error checking if change is submittable", e);
+      throw new OrmRuntimeException("Could not determine problems for the change", e);
     }
 
     if (!visible) {
@@ -297,8 +303,8 @@
 
     boolean enabled;
     try {
-      enabled = mergeableProvider.get().apply(resource).mergeable;
-    } catch (RestApiException | OrmException | IOException e) {
+      enabled = cd.isMergeable();
+    } catch (OrmException e) {
       throw new OrmRuntimeException("Could not determine mergeability", e);
     }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
index f05a1d4..773d665 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
@@ -137,7 +137,7 @@
 
       updateSubmoduleSubscriptions();
       updateSuperProjects(destBranch, rw, mergeTip.getId().toObjectId(), null);
-    } catch (OrmException e) {
+    } catch (OrmException | IOException e) {
       throw new SubmoduleException("Cannot open database", e);
     } finally {
       if (schema != null) {
@@ -210,7 +210,8 @@
   }
 
   private void updateSuperProjects(final Branch.NameKey updatedBranch, RevWalk myRw,
-      final ObjectId mergedCommit, final String msg) throws SubmoduleException {
+      final ObjectId mergedCommit, final String msg) throws SubmoduleException,
+      IOException {
     try {
       final List<SubmoduleSubscription> subscribers =
           schema.submoduleSubscriptions().bySubmodule(updatedBranch).toList();
@@ -236,6 +237,7 @@
                 && (c.getStatusCode() == CommitMergeStatus.CLEAN_MERGE
                     || c.getStatusCode() == CommitMergeStatus.CLEAN_PICK
                     || c.getStatusCode() == CommitMergeStatus.CLEAN_REBASE)) {
+              myRw.parseBody(c);
               sb.append("\n")
                 .append(c.getFullMessage());
             }