Support branch redirecting from a deleted or non-existent branch to HEAD.

BranchRedirectFilter uses the ViewFilter to obtain the GitilesView. The GitilesView is not created for a deleted branch. This causes `BranchRedirectFilter to not redirect as expected. Since branch redirect is used primarily to migrate from master to main, and master to be eventually deleted. HEAD would be set to main since master is being deleted. This makes HEAD a correct place to redirect to.

PiperOrigin-RevId: 411156730
Change-Id: I4193a86d36e3d46cb19abf9c7b52a94b1feef5c1
diff --git a/java/com/google/gitiles/RevisionParser.java b/java/com/google/gitiles/RevisionParser.java
index b736f7f..5a5104f 100644
--- a/java/com/google/gitiles/RevisionParser.java
+++ b/java/com/google/gitiles/RevisionParser.java
@@ -26,6 +26,7 @@
 import org.eclipse.jgit.errors.AmbiguousObjectException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.errors.RevisionSyntaxException;
+import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevCommit;
@@ -107,6 +108,9 @@
     if (path.startsWith("/")) {
       path = path.substring(1);
     }
+    if (Constants.HEAD.equals(path)) {
+      path = repo.getFullBranch();
+    }
     try (RevWalk walk = new RevWalk(repo)) {
       walk.setRetainBody(false);
 
diff --git a/java/com/google/gitiles/ViewFilter.java b/java/com/google/gitiles/ViewFilter.java
index 25d6d7e..c8b3639 100644
--- a/java/com/google/gitiles/ViewFilter.java
+++ b/java/com/google/gitiles/ViewFilter.java
@@ -28,6 +28,7 @@
 import javax.servlet.http.HttpServletResponse;
 import org.eclipse.jgit.http.server.ServletUtils;
 import org.eclipse.jgit.http.server.glue.WrappedRequest;
+import org.eclipse.jgit.lib.Constants;
 
 /** Filter to parse URLs and convert them to {@link GitilesView}s. */
 public class ViewFilter extends AbstractHttpFilter {
@@ -98,6 +99,10 @@
       throws IOException, ServletException {
     GitilesView.Builder view = parse(req);
     if (view == null) {
+      String path = "/" + Constants.HEAD;
+      view = parse(req, path);
+    }
+    if (view == null) {
       throw new GitilesRequestFailureException(FailureReason.CANNOT_PARSE_GITILES_VIEW);
     }
 
@@ -132,12 +137,16 @@
   }
 
   private GitilesView.Builder parse(HttpServletRequest req) throws IOException {
+    String path = getRegexGroup(req, 3);
+    return parse(req, path);
+  }
+
+  private GitilesView.Builder parse(HttpServletRequest req, String path) throws IOException {
     String repoName = trimLeadingSlash(getRegexGroup(req, 1));
     if (repoName.isEmpty()) {
       return GitilesView.hostIndex();
     }
     String command = getRegexGroup(req, 2);
-    String path = getRegexGroup(req, 3);
 
     if (command.isEmpty()) {
       return parseNoCommand(req, repoName);
diff --git a/javatests/com/google/gitiles/ViewFilterTest.java b/javatests/com/google/gitiles/ViewFilterTest.java
index 66cd5d8..ae7eda4 100644
--- a/javatests/com/google/gitiles/ViewFilterTest.java
+++ b/javatests/com/google/gitiles/ViewFilterTest.java
@@ -73,6 +73,16 @@
   }
 
   @Test
+  public void autoCommand_branchRedirect() throws Exception {
+    RevCommit parent = repo.commit().create();
+    RevCommit head = repo.branch("HEAD").commit().parent(parent).create();
+
+    GitilesView view = getView("/repo/+/master");
+    assertThat(view.getType()).isEqualTo(Type.REVISION);
+    assertThat(view.getRevision().getName()).isEqualTo(head.name());
+  }
+
+  @Test
   public void hostIndex() throws Exception {
     GitilesView view = getView("/");
     assertThat(view.getType()).isEqualTo(Type.HOST_INDEX);