Переглянути джерело

Merge pull request #33771 from overleaf/mj-git-bridge-default-main

[git-bridge] Default new projects to main rather than master

GitOrigin-RevId: 3d7d60c0aab6e5d0d10d282d6d491d4f735ed94c
David 2 місяців тому
батько
коміт
f27112179a
10 змінених файлів з 191 додано та 5 видалено
  1. 3 0
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/repo/GitProjectRepo.java
  2. 69 5
      services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/application/WLGitBridgeIntegrationTest.java
  3. 25 0
      services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/bridge/repo/GitProjectRepoTest.java
  4. 1 0
      services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/111111111111111111111111/foo/bar/test.tex
  5. 1 0
      services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/111111111111111111111111/main.tex
  6. BIN
      services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/111111111111111111111111/overleaf-white-410.png
  7. BIN
      services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/222222222222222222222222/editor-versions-a7e4de19d015c3e7477e3f7eaa6c418e.png
  8. 1 0
      services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/222222222222222222222222/foo/bar/test.tex
  9. 1 0
      services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/222222222222222222222222/main.tex
  10. 90 0
      services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/state.json

+ 3 - 0
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/repo/GitProjectRepo.java

@@ -14,6 +14,7 @@ import org.apache.commons.io.IOUtils;
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.ResetCommand;
 import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
@@ -83,6 +84,8 @@ public class GitProjectRepo implements ProjectRepo {
       return;
     }
     repo.create();
+    // Set default branch to "main" for new projects
+    repo.updateRef(Constants.HEAD).link("refs/heads/main");
   }
 
   @Override

+ 69 - 5
services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/application/WLGitBridgeIntegrationTest.java

@@ -449,6 +449,17 @@ public class WLGitBridgeIntegrationTest {
                           .build());
                 }
               });
+          put(
+              "masterBranchSurvivesSwap",
+              new HashMap<String, SnapshotAPIState>() {
+                {
+                  put(
+                      "state",
+                      new SnapshotAPIStateBuilder(
+                              getResourceAsStream("/masterBranchSurvivesSwap/state/state.json"))
+                          .build());
+                }
+              });
         }
       };
 
@@ -522,6 +533,13 @@ public class WLGitBridgeIntegrationTest {
     assertEquals(0, runtime.exec("git pull", null, dir).waitFor());
   }
 
+  private String gitBranch(File dir) throws IOException, InterruptedException {
+    Process proc =
+        runtime.exec(new String[] {"git", "rev-parse", "--abbrev-ref", "HEAD"}, null, dir);
+    assertEquals(0, proc.waitFor());
+    return IOUtils.toString(proc.getInputStream(), StandardCharsets.UTF_8).trim();
+  }
+
   @Test
   public void canCloneARepository() throws IOException, GitAPIException, InterruptedException {
     server = new MockSnapshotServer(3857, getResource("/canCloneARepository").toFile());
@@ -807,7 +825,7 @@ public class WLGitBridgeIntegrationTest {
         "remote: hint: hello world.png (rename to: hello_world.png)",
         "remote: hint: an image.jpg (rename to: an_image.jpg)",
         "To " + gitRemoteUrl(port),
-        "! [remote rejected] master -> master (invalid files)",
+        "! [remote rejected] main -> main (invalid files)",
         "error: failed to push some refs to '" + gitRemoteUrl(port) + "'");
   }
 
@@ -835,7 +853,7 @@ public class WLGitBridgeIntegrationTest {
         "remote: hint: project: no main file",
         "remote: hint: The project would have no (editable) main .tex file.",
         "To " + gitRemoteUrl(port),
-        "! [remote rejected] master -> master (invalid project)",
+        "! [remote rejected] main -> main (invalid project)",
         "error: failed to push some refs to '" + gitRemoteUrl(port) + "'");
   }
 
@@ -864,7 +882,7 @@ public class WLGitBridgeIntegrationTest {
         "remote: hint: There was an internal error with the Overleaf server.",
         "remote: hint: Please contact Overleaf.",
         "To " + gitRemoteUrl(port),
-        "! [remote rejected] master -> master (Overleaf error)",
+        "! [remote rejected] main -> main (Overleaf error)",
         "error: failed to push some refs to '" + gitRemoteUrl(port) + "'");
   }
 
@@ -896,7 +914,7 @@ public class WLGitBridgeIntegrationTest {
         "remote: hint: You have 1 invalid files in your Overleaf project:",
         "remote: hint: file1.exe (invalid file extension)",
         "To " + gitRemoteUrl(port),
-        "! [remote rejected] master -> master (invalid files)",
+        "! [remote rejected] main -> main (invalid files)",
         "error: failed to push some refs to '" + gitRemoteUrl(port) + "'");
   }
 
@@ -1012,13 +1030,59 @@ public class WLGitBridgeIntegrationTest {
     assertFalse(testProj2ServerDir.exists());
   }
 
+  @Test
+  public void masterBranchSurvivesSwap() throws Exception {
+    int mockServerPort = 4010;
+    server =
+        new MockSnapshotServer(mockServerPort, getResource("/masterBranchSurvivesSwap").toFile());
+    server.start();
+    server.setState(states.get("masterBranchSurvivesSwap").get("state"));
+    wlgb =
+        new GitBridgeApp(
+            new String[] {
+              makeConfigFile(0, mockServerPort, new SwapJobConfig(1, 0, 0, 250, null, true))
+            });
+    wlgb.run();
+    File rootGitDir = new File(wlgb.config.getRootGitDirectory());
+    File proj1ServerDir = new File(rootGitDir, PROJECT_ID1);
+    File proj2ServerDir = new File(rootGitDir, PROJECT_ID2);
+
+    // Clone project 1 — created with default branch "main"
+    File proj1Dir = gitClone(PROJECT_ID1, wlgb.getPort(), dir);
+    assertEquals("main", gitBranch(proj1Dir));
+    assertTrue(proj1ServerDir.exists());
+
+    // Simulate a legacy repo: rewrite server-side HEAD to master
+    assertEquals(
+        0,
+        runtime
+            .exec(new String[] {"git", "branch", "-m", "main", "master"}, null, proj1ServerDir)
+            .waitFor());
+
+    // Clone project 2 — triggers eviction of project 1
+    gitClone(PROJECT_ID2, wlgb.getPort(), dir);
+    while (proj1ServerDir.exists())
+      ;
+    assertFalse(proj1ServerDir.exists());
+    assertTrue(proj2ServerDir.exists());
+
+    // Re-clone project 1 — triggers restore from swap
+    FileUtils.deleteDirectory(proj1Dir);
+    File proj1DirRestored = gitClone(PROJECT_ID1, wlgb.getPort(), dir);
+    while (proj2ServerDir.exists())
+      ;
+
+    // Verify the restored repo still uses "master"
+    assertEquals("master", gitBranch(proj1DirRestored));
+  }
+
   private static List<String> expectedPushSubmodule(int port) {
     return Arrays.asList(
         "remote: hint: Your Git repository contains a reference we cannot resolve.",
         "remote: hint: If your project contains a Git submodule,",
         "remote: hint: please remove it and try again.",
         "To " + gitRemoteUrl(port),
-        "! [remote rejected] master -> master (invalid git repo)",
+        "! [remote rejected] main -> main (invalid git repo)",
         "error: failed to push some refs to '" + gitRemoteUrl(port) + "'");
   }
 

+ 25 - 0
services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/bridge/repo/GitProjectRepoTest.java

@@ -13,6 +13,7 @@ import java.nio.file.Paths;
 import java.util.*;
 import java.util.function.Supplier;
 import org.apache.commons.io.FileUtils;
+import org.eclipse.jgit.lib.Constants;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -169,4 +170,28 @@ public class GitProjectRepoTest {
     withoutIncoming.deleteIncomingPacks();
     assertTrue(FileUtil.directoryDeepEquals(actual, expected));
   }
+
+  @Test
+  public void initRepoSetsDefaultBranchToMain() throws IOException {
+    FSGitRepoStore store =
+        new FSGitRepoStore(tmpFolder.newFolder("newrepos").getAbsolutePath(), Optional.empty());
+    GitProjectRepo newRepo = GitProjectRepo.fromName("testproject");
+    newRepo.initRepo(store);
+    assertEquals("refs/heads/main", newRepo.getJGitRepository().getFullBranch());
+  }
+
+  @Test
+  public void initRepoDoesNotRewriteExistingMasterRepoToMain() throws IOException {
+    FSGitRepoStore store =
+        new FSGitRepoStore(tmpFolder.newFolder("legacyrepos").getAbsolutePath(), Optional.empty());
+    GitProjectRepo newRepo = GitProjectRepo.fromName("testproject");
+    newRepo.initRepo(store);
+    newRepo.getJGitRepository().updateRef(Constants.HEAD).link("refs/heads/master");
+    assertEquals("refs/heads/master", newRepo.getJGitRepository().getFullBranch());
+
+    GitProjectRepo existingRepo = GitProjectRepo.fromName("testproject");
+    existingRepo.initRepo(store);
+
+    assertEquals("refs/heads/master", existingRepo.getJGitRepository().getFullBranch());
+  }
 }

+ 1 - 0
services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/111111111111111111111111/foo/bar/test.tex

@@ -0,0 +1 @@
+This text is from another file.

+ 1 - 0
services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/111111111111111111111111/main.tex

@@ -0,0 +1 @@
+content

BIN
services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/111111111111111111111111/overleaf-white-410.png


BIN
services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/222222222222222222222222/editor-versions-a7e4de19d015c3e7477e3f7eaa6c418e.png


+ 1 - 0
services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/222222222222222222222222/foo/bar/test.tex

@@ -0,0 +1 @@
+a different one

+ 1 - 0
services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/222222222222222222222222/main.tex

@@ -0,0 +1 @@
+different content

+ 90 - 0
services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/masterBranchSurvivesSwap/state/state.json

@@ -0,0 +1,90 @@
+[
+  {
+    "project": "111111111111111111111111",
+    "getDoc": {
+      "versionID": 1,
+      "createdAt": "2014-11-30T18:40:58.123Z",
+      "email": "jdleesmiller+1@gmail.com",
+      "name": "John+1"
+    },
+    "getSavedVers": [
+      {
+        "versionID": 1,
+        "comment": "added more info on doc GET and error details\n",
+        "email": "jdleesmiller+1@gmail.com",
+        "name": "John+1",
+        "createdAt": "2014-11-30T18:47:01.456Z"
+      }
+    ],
+    "getForVers": [
+      {
+        "versionID": 1,
+        "srcs": [
+          {
+            "content": "content\n",
+            "path": "main.tex"
+          },
+          {
+            "content": "This text is from another file.",
+            "path": "foo/bar/test.tex"
+          }
+        ],
+        "atts": [
+          {
+            "url": "http://127.0.0.1:4010/state/111111111111111111111111/overleaf-white-410.png",
+            "path": "overleaf-white-410.png"
+          }
+        ]
+      }
+    ],
+    "push": "success",
+    "postback": {
+      "type": "success",
+      "versionID": 2
+    }
+  },
+  {
+    "project": "222222222222222222222222",
+    "getDoc": {
+      "versionID": 1,
+      "createdAt": "2014-11-30T18:40:58.123Z",
+      "email": "jdleesmiller+1@gmail.com",
+      "name": "John+1"
+    },
+    "getSavedVers": [
+      {
+        "versionID": 1,
+        "comment": "added more info on doc GET and error details",
+        "email": "jdleesmiller+1@gmail.com",
+        "name": "John+1",
+        "createdAt": "2014-11-30T18:47:01.456Z"
+      }
+    ],
+    "getForVers": [
+      {
+        "versionID": 1,
+        "srcs": [
+          {
+            "content": "different content\n",
+            "path": "main.tex"
+          },
+          {
+            "content": "a different one",
+            "path": "foo/bar/test.tex"
+          }
+        ],
+        "atts": [
+          {
+            "url": "http://127.0.0.1:4010/state/222222222222222222222222/editor-versions-a7e4de19d015c3e7477e3f7eaa6c418e.png",
+            "path": "editor-versions-a7e4de19d015c3e7477e3f7eaa6c418e.png"
+          }
+        ]
+      }
+    ],
+    "push": "success",
+    "postback": {
+      "type": "success",
+      "versionID": 2
+    }
+  }
+]