Merge changes from topic "gr-apply-fix-dialog-to-ts"

* changes:
  Replace ChangeNum with NumericChangeId
  Convert files to typescript
  Rename files to preserve history
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index d615204..00571b8 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -719,6 +719,7 @@
         parseRegularCommand(cmd);
       }
 
+      Map<BranchNameKey, ReceiveCommand> branches;
       try (BatchUpdate bu =
               batchUpdateFactory.create(
                   project.getNameKey(), user.materializedCopy(), TimeUtil.nowTs());
@@ -737,41 +738,40 @@
         }
         logger.atFine().log("Added %d additional ref updates", added);
         bu.execute();
+        branches = bu.getSuccessfullyUpdatedBranches(/* dryrun=*/ false);
       } catch (UpdateException | RestApiException e) {
         throw new StorageException(e);
       }
 
-      Set<BranchNameKey> branches = new HashSet<>();
-      for (ReceiveCommand c : cmds) {
-        // Most post-update steps should happen in UpdateOneRefOp#postUpdate. The only steps that
-        // should happen in this loops are things that can't happen within one BatchUpdate because
-        // they involve kicking off an additional BatchUpdate.
-        if (c.getResult() != OK) {
-          continue;
-        }
-        if (isHead(c) || isConfig(c)) {
-          switch (c.getType()) {
-            case CREATE:
-            case UPDATE:
-            case UPDATE_NONFASTFORWARD:
-              Task closeProgress = progress.beginSubTask("closed", UNKNOWN);
-              autoCloseChanges(c, closeProgress);
-              closeProgress.end();
-              branches.add(BranchNameKey.create(project.getNameKey(), c.getRefName()));
-              break;
+      branches.values().stream()
+          .filter(c -> isHead(c) || isConfig(c))
+          .forEach(
+              c -> {
+                // Most post-update steps should happen in UpdateOneRefOp#postUpdate. The only steps
+                // that
+                // should happen in this loops are things that can't happen within one BatchUpdate
+                // because
+                // they involve kicking off an additional BatchUpdate.
+                switch (c.getType()) {
+                  case CREATE:
+                  case UPDATE:
+                  case UPDATE_NONFASTFORWARD:
+                    Task closeProgress = progress.beginSubTask("closed", UNKNOWN);
+                    autoCloseChanges(c, closeProgress);
+                    closeProgress.end();
+                    break;
 
-            case DELETE:
-              break;
-          }
-        }
-      }
+                  case DELETE:
+                    break;
+                }
+              });
 
       // Update superproject gitlinks if required.
       if (!branches.isEmpty()) {
         try (MergeOpRepoManager orm = ormProvider.get()) {
           orm.setContext(TimeUtil.nowTs(), user, NotifyResolver.Result.none());
           SubmoduleOp op = subOpFactory.create(branches, orm);
-          op.updateSuperProjects();
+          op.updateSuperProjects(false);
         } catch (RestApiException e) {
           logger.atWarning().withCause(e).log("Can't update the superprojects");
         }
diff --git a/java/com/google/gerrit/server/submit/MergeOp.java b/java/com/google/gerrit/server/submit/MergeOp.java
index 8d3324f..5ce7c03 100644
--- a/java/com/google/gerrit/server/submit/MergeOp.java
+++ b/java/com/google/gerrit/server/submit/MergeOp.java
@@ -615,9 +615,10 @@
           getSubmitStrategies(
               toSubmit, updateOrderCalculator, submoduleCommits, subscriptionGraph, dryrun);
       this.allProjects = updateOrderCalculator.getProjectsInOrder();
+      List<BatchUpdate> batchUpdates = orm.batchUpdates(allProjects);
       try {
         BatchUpdate.execute(
-            orm.batchUpdates(allProjects),
+            batchUpdates,
             new SubmitStrategyListener(submitInput, strategies, commitStatus),
             dryrun);
       } finally {
@@ -625,6 +626,11 @@
         // successful. This is why we must to collect the updated changes also when an exception was
         // thrown.
         strategies.forEach(s -> updatedChanges.putAll(s.getUpdatedChanges()));
+
+        // Do not leave executed BatchUpdates in the OpenRepos
+        if (!dryrun) {
+          orm.resetUpdates(ImmutableSet.copyOf(this.allProjects));
+        }
       }
     } catch (NoSuchProjectException e) {
       throw new ResourceNotFoundException(e.getMessage());
diff --git a/java/com/google/gerrit/server/submit/MergeOpRepoManager.java b/java/com/google/gerrit/server/submit/MergeOpRepoManager.java
index b32c712..e31a841 100644
--- a/java/com/google/gerrit/server/submit/MergeOpRepoManager.java
+++ b/java/com/google/gerrit/server/submit/MergeOpRepoManager.java
@@ -18,6 +18,7 @@
 import static com.google.gerrit.server.project.ProjectCache.noSuchProject;
 import static java.util.Objects.requireNonNull;
 
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
 import com.google.gerrit.entities.BranchNameKey;
 import com.google.gerrit.entities.Project;
@@ -119,6 +120,14 @@
       return update;
     }
 
+    // We want to reuse the open repo BUT not the BatchUpdate (because they are already executed)
+    public void resetUpdate() {
+      if (update != null) {
+        update.close();
+        update = null;
+      }
+    }
+
     private void close() {
       if (update != null) {
         update.close();
@@ -206,6 +215,13 @@
     return updates;
   }
 
+  public void resetUpdates(ImmutableSet<Project.NameKey> projects)
+      throws NoSuchProjectException, IOException {
+    for (Project.NameKey project : projects) {
+      getRepo(project).resetUpdate();
+    }
+  }
+
   @Override
   public void close() {
     for (OpenRepo repo : openRepos.values()) {
diff --git a/java/com/google/gerrit/server/submit/SubmoduleOp.java b/java/com/google/gerrit/server/submit/SubmoduleOp.java
index e6f2247..64710c3 100644
--- a/java/com/google/gerrit/server/submit/SubmoduleOp.java
+++ b/java/com/google/gerrit/server/submit/SubmoduleOp.java
@@ -19,6 +19,7 @@
 import com.google.gerrit.entities.Project;
 import com.google.gerrit.exceptions.StorageException;
 import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.server.git.CodeReviewCommit;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.submit.MergeOpRepoManager.OpenRepo;
 import com.google.gerrit.server.update.BatchUpdate;
@@ -28,7 +29,8 @@
 import com.google.inject.Singleton;
 import java.io.IOException;
 import java.util.LinkedHashSet;
-import java.util.Set;
+import java.util.Map;
+import org.eclipse.jgit.transport.ReceiveCommand;
 
 public class SubmoduleOp {
 
@@ -45,36 +47,47 @@
       this.submoduleCommitsFactory = submoduleCommitsFactory;
     }
 
-    public SubmoduleOp create(Set<BranchNameKey> updatedBranches, MergeOpRepoManager orm)
+    public SubmoduleOp create(
+        Map<BranchNameKey, ReceiveCommand> updatedBranches, MergeOpRepoManager orm)
         throws SubmoduleConflictException {
       return new SubmoduleOp(
+          updatedBranches,
           orm,
-          subscriptionGraphFactory.compute(updatedBranches, orm),
+          subscriptionGraphFactory.compute(updatedBranches.keySet(), orm),
           submoduleCommitsFactory.create(orm));
     }
   }
 
+  private final Map<BranchNameKey, ReceiveCommand> updatedBranches;
   private final MergeOpRepoManager orm;
   private final SubscriptionGraph subscriptionGraph;
   private final SubmoduleCommits submoduleCommits;
   private final UpdateOrderCalculator updateOrderCalculator;
 
   private SubmoduleOp(
+      Map<BranchNameKey, ReceiveCommand> updatedBranches,
       MergeOpRepoManager orm,
       SubscriptionGraph subscriptionGraph,
       SubmoduleCommits submoduleCommits) {
+    this.updatedBranches = updatedBranches;
     this.orm = orm;
     this.subscriptionGraph = subscriptionGraph;
     this.submoduleCommits = submoduleCommits;
     this.updateOrderCalculator = new UpdateOrderCalculator(subscriptionGraph);
   }
 
-  public void updateSuperProjects() throws RestApiException {
+  public void updateSuperProjects(boolean dryrun) throws RestApiException {
     ImmutableSet<Project.NameKey> projects = updateOrderCalculator.getProjectsInOrder();
     if (projects == null) {
       return;
     }
 
+    if (dryrun) {
+      // On dryrun, the refs hasn't been updated.
+      // force the new tips on submoduleCommits
+      forceRefTips(updatedBranches, submoduleCommits);
+    }
+
     LinkedHashSet<Project.NameKey> superProjects = new LinkedHashSet<>();
     try {
       GitlinkOp.Factory gitlinkOpFactory =
@@ -90,9 +103,29 @@
           }
         }
       }
-      BatchUpdate.execute(orm.batchUpdates(superProjects), BatchUpdateListener.NONE, false);
+      BatchUpdate.execute(orm.batchUpdates(superProjects), BatchUpdateListener.NONE, dryrun);
     } catch (UpdateException | IOException | NoSuchProjectException e) {
       throw new StorageException("Cannot update gitlinks", e);
     }
   }
+
+  private void forceRefTips(
+      Map<BranchNameKey, ReceiveCommand> updatedBranches, SubmoduleCommits submoduleCommits) {
+    // This is dryrun, all commands succeeded (no need to filter success).
+    for (Map.Entry<BranchNameKey, ReceiveCommand> updateBranch : updatedBranches.entrySet()) {
+      try {
+        ReceiveCommand command = updateBranch.getValue();
+        if (command.getType() == ReceiveCommand.Type.DELETE) {
+          continue;
+        }
+
+        BranchNameKey branchNameKey = updateBranch.getKey();
+        OpenRepo openRepo = orm.getRepo(branchNameKey.project());
+        CodeReviewCommit fakeTip = openRepo.rw.parseCommit(command.getNewId());
+        submoduleCommits.addBranchTip(branchNameKey, fakeTip);
+      } catch (NoSuchProjectException | IOException e) {
+        throw new StorageException("Cannot find branch tip target in dryrun", e);
+      }
+    }
+  }
 }
diff --git a/java/com/google/gerrit/server/update/BatchUpdate.java b/java/com/google/gerrit/server/update/BatchUpdate.java
index 166e88d..eb4962d 100644
--- a/java/com/google/gerrit/server/update/BatchUpdate.java
+++ b/java/com/google/gerrit/server/update/BatchUpdate.java
@@ -20,6 +20,7 @@
 import static com.google.common.flogger.LazyArgs.lazy;
 import static java.util.Comparator.comparing;
 import static java.util.Objects.requireNonNull;
+import static java.util.stream.Collectors.toMap;
 import static java.util.stream.Collectors.toSet;
 
 import com.google.common.base.Throwables;
@@ -33,6 +34,7 @@
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.gerrit.common.Nullable;
+import com.google.gerrit.entities.BranchNameKey;
 import com.google.gerrit.entities.Change;
 import com.google.gerrit.entities.PatchSet;
 import com.google.gerrit.entities.PatchSet.Id;
@@ -82,6 +84,7 @@
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.transport.PushCertificate;
 import org.eclipse.jgit.transport.ReceiveCommand;
+import org.eclipse.jgit.transport.ReceiveCommand.Result;
 
 /**
  * Helper for a set of change updates that should be applied to the NoteDb database.
@@ -462,6 +465,17 @@
     return repoView != null ? repoView.getCommands().getCommands() : ImmutableMap.of();
   }
 
+  /**
+   * Return the references successfully updated by this BatchUpdate with their command. In dryrun,
+   * we assume all updates were successful.
+   */
+  public Map<BranchNameKey, ReceiveCommand> getSuccessfullyUpdatedBranches(boolean dryrun) {
+    return getRefUpdates().entrySet().stream()
+        .filter(entry -> dryrun || entry.getValue().getResult() == Result.OK)
+        .collect(
+            toMap(entry -> BranchNameKey.create(project, entry.getKey()), Map.Entry::getValue));
+  }
+
   public BatchUpdate addOp(Change.Id id, BatchUpdateOp op) {
     checkArgument(!(op instanceof InsertChangeOp), "use insertChange");
     requireNonNull(op);