diff --git a/services/git-bridge/pom.xml b/services/git-bridge/pom.xml
index 74eaefe50d..4499489564 100644
--- a/services/git-bridge/pom.xml
+++ b/services/git-bridge/pom.xml
@@ -9,6 +9,7 @@
1.0-SNAPSHOT
UTF-8
+
@@ -22,6 +23,15 @@
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ -Djdk.net.URLClassPath.disableClassPathURLCheck=true
+
+
maven-assembly-plugin
diff --git a/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/Bridge.java b/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/Bridge.java
index 9ee76263de..3c543f50f5 100644
--- a/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/Bridge.java
+++ b/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/Bridge.java
@@ -37,6 +37,7 @@ import uk.ac.ic.wlgitbridge.server.PostbackContents;
import uk.ac.ic.wlgitbridge.server.PostbackHandler;
import uk.ac.ic.wlgitbridge.snapshot.base.MissingRepositoryException;
import uk.ac.ic.wlgitbridge.snapshot.base.ForbiddenException;
+import uk.ac.ic.wlgitbridge.snapshot.getdoc.GetDocResult;
import uk.ac.ic.wlgitbridge.snapshot.getforversion.SnapshotAttachment;
import uk.ac.ic.wlgitbridge.snapshot.push.PostbackManager;
import uk.ac.ic.wlgitbridge.snapshot.push.PostbackPromise;
@@ -299,7 +300,7 @@ public class Bridge {
* Synchronises the given repository with Overleaf.
*
* It acquires the project lock and calls
- * {@link #getUpdatedRepoCritical(Optional, String)}.
+ * {@link #getUpdatedRepoCritical(Optional, String, GetDocResult)}.
* @param oauth2 The oauth2 to use
* @param projectName The name of the project
* @throws IOException
@@ -310,11 +311,13 @@ public class Bridge {
String projectName
) throws IOException, GitUserException {
try (LockGuard __ = lock.lockGuard(projectName)) {
- if (!snapshotAPI.projectExists(oauth2, projectName)) {
+ Optional maybeDoc = snapshotAPI.getDoc(oauth2, projectName);
+ if (!maybeDoc.isPresent()) {
throw new RepositoryNotFoundException(projectName);
}
+ GetDocResult doc = maybeDoc.get();
Log.info("[{}] Updating repository", projectName);
- return getUpdatedRepoCritical(oauth2, projectName);
+ return getUpdatedRepoCritical(oauth2, projectName, doc);
}
}
@@ -346,14 +349,51 @@ public class Bridge {
*/
private ProjectRepo getUpdatedRepoCritical(
Optional oauth2,
- String projectName
+ String projectName,
+ GetDocResult doc
) throws IOException, GitUserException {
ProjectRepo repo;
ProjectState state = dbStore.getProjectState(projectName);
switch (state) {
case NOT_PRESENT:
- repo = repoStore.initRepo(projectName);
- break;
+ Log.info("[{}] Repo not present", projectName);
+ String migratedFromID = doc.getMigratedFromID();
+ if (migratedFromID != null) {
+ Log.info("[{}] Has a migratedFromId: {}", projectName, migratedFromID);
+ try (LockGuard __ = lock.lockGuard(migratedFromID)) {
+ ProjectState sourceState = dbStore.getProjectState(migratedFromID);
+ switch (sourceState) {
+ case NOT_PRESENT:
+ // Normal init-repo
+ Log.info("[{}] migrated-from project not present, proceed as normal",
+ projectName
+ );
+ repo = repoStore.initRepo(projectName);
+ break;
+ case SWAPPED:
+ // Swap back and then copy
+ swapJob.restore(migratedFromID);
+ /* Fallthrough */
+ default:
+ // Copy data, and set version to zero
+ Log.info("[{}] Init from other project: {}",
+ projectName,
+ migratedFromID
+ );
+ repo = repoStore.initRepoFromExisting(projectName, migratedFromID);
+ dbStore.setLatestVersionForProject(migratedFromID, 0);
+ dbStore.setLastAccessedTime(
+ migratedFromID,
+ Timestamp.valueOf(LocalDateTime.now())
+
+ );
+ }
+ }
+ break;
+ } else {
+ repo = repoStore.initRepo(projectName);
+ break;
+ }
case SWAPPED:
swapJob.restore(projectName);
/* Fallthrough */
diff --git a/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/repo/FSGitRepoStore.java b/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/repo/FSGitRepoStore.java
index a3bfe30928..47a7eede67 100644
--- a/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/repo/FSGitRepoStore.java
+++ b/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/repo/FSGitRepoStore.java
@@ -4,6 +4,7 @@ import com.google.api.client.repackaged.com.google.common.base.Preconditions;
import org.apache.commons.io.FileUtils;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
+import uk.ac.ic.wlgitbridge.util.Log;
import uk.ac.ic.wlgitbridge.util.Project;
import uk.ac.ic.wlgitbridge.util.Tar;
@@ -74,6 +75,27 @@ public class FSGitRepoStore implements RepoStore {
ret, Optional.of(maxFileSize), Optional.empty());
}
+ @Override
+ public ProjectRepo initRepoFromExisting(
+ String project, String fromProject
+ ) throws IOException {
+ String repoRoot = getRepoStorePath();
+ String sourcePath = repoRoot + "/" + fromProject;
+ String destinationPath = repoRoot + "/" + project;
+ Log.info("[{}] Init repo by copying data from: {}, to: {}",
+ project,
+ sourcePath,
+ destinationPath
+ );
+ File source = new File(sourcePath);
+ File destination = new File(destinationPath);
+ FileUtils.copyDirectory(source, destination);
+ GitProjectRepo ret = GitProjectRepo.fromName(project);
+ ret.useExistingRepository(this);
+ return new WalkOverrideGitRepo(
+ ret, Optional.of(maxFileSize), Optional.empty());
+ }
+
@Override
public ProjectRepo getExistingRepo(String project) throws IOException {
GitProjectRepo ret = GitProjectRepo.fromName(project);
diff --git a/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/repo/RepoStore.java b/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/repo/RepoStore.java
index a5eb289942..18bea89cd5 100644
--- a/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/repo/RepoStore.java
+++ b/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/repo/RepoStore.java
@@ -22,6 +22,8 @@ public interface RepoStore {
ProjectRepo initRepo(String project) throws IOException;
+ ProjectRepo initRepoFromExisting(String project, String fromProject) throws IOException;
+
ProjectRepo getExistingRepo(String project) throws IOException;
ProjectRepo useJGitRepo(Repository repo, ObjectId commitId);
diff --git a/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/snapshot/SnapshotApiFacade.java b/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/snapshot/SnapshotApiFacade.java
index f9085febcb..9bbcf09142 100644
--- a/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/snapshot/SnapshotApiFacade.java
+++ b/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/snapshot/SnapshotApiFacade.java
@@ -44,6 +44,20 @@ public class SnapshotApiFacade {
}
}
+ public Optional getDoc(
+ Optional oauth2,
+ String projectName
+ ) throws FailedConnectionException, GitUserException {
+ try {
+ GetDocResult doc = SnapshotApi
+ .getResult(api.getDoc(oauth2, projectName));
+ doc.getVersionID();
+ return Optional.of(doc);
+ } catch (InvalidProjectException e) {
+ return Optional.empty();
+ }
+ }
+
public Deque getSnapshots(
Optional oauth2,
String projectName,
diff --git a/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/base/MissingRepositoryException.java b/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/base/MissingRepositoryException.java
index c39f6c2481..9578c18f27 100644
--- a/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/base/MissingRepositoryException.java
+++ b/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/base/MissingRepositoryException.java
@@ -15,11 +15,31 @@ public class MissingRepositoryException extends SnapshotAPIException {
"If this problem persists, please contact us."
);
- public static final List EXPORTED_TO_V2 = Arrays.asList(
- "This Overleaf project has been moved to Overleaf v2, and git access is temporarily unsupported.",
- "",
- "See https://www.overleaf.com/help/342 for more information."
- );
+ static List buildExportedToV2Message(String remoteUrl) {
+ if (remoteUrl == null) {
+ return Arrays.asList(
+ "This Overleaf project has been moved to Overleaf v2 and cannot be used with git at this time.",
+ "",
+ "If this error persists, please contact us at support@overleaf.com, or",
+ "see https://www.overleaf.com/help/342 for more information."
+ );
+ } else {
+ return Arrays.asList(
+ "This Overleaf project has been moved to Overleaf v2 and has a new identifier.",
+ "Please update your remote to:",
+ "",
+ " " + remoteUrl,
+ "",
+ "Assuming you are using the default \"origin\" remote, the following commands",
+ "will change the remote for you:",
+ "",
+ " git remote set-url origin " + remoteUrl,
+ "",
+ "If this does not work, please contact us at support@overleaf.com, or",
+ "see https://www.overleaf.com/help/342 for more information."
+ );
+ }
+ }
private List descriptionLines;
diff --git a/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/base/Request.java b/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/base/Request.java
index 34fabb794e..65dc8af0b9 100644
--- a/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/base/Request.java
+++ b/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/base/Request.java
@@ -79,9 +79,17 @@ public abstract class Request {
try {
JsonObject json = Instance.gson.fromJson(httpCause.getContent(), JsonObject.class);
String message = json.get("message").getAsString();
+ String newRemote;
+ if (json.has("newRemote")) {
+ newRemote = json.get("newRemote").getAsString();
+ } else {
+ newRemote = null;
+ }
if ("Exported to v2".equals(message)) {
- throw new MissingRepositoryException(MissingRepositoryException.EXPORTED_TO_V2);
+ throw new MissingRepositoryException(
+ MissingRepositoryException.buildExportedToV2Message(newRemote)
+ );
}
} catch (IllegalStateException
| ClassCastException
diff --git a/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getdoc/GetDocResult.java b/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getdoc/GetDocResult.java
index 6b47a3985d..3fafb394f0 100644
--- a/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getdoc/GetDocResult.java
+++ b/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getdoc/GetDocResult.java
@@ -19,6 +19,7 @@ public class GetDocResult extends Result {
private int error;
private int versionID;
+ private String migratedFromID;
private String createdAt;
private WLUser user;
@@ -37,7 +38,8 @@ public class GetDocResult extends Result {
int versionID,
String createdAt,
String email,
- String name
+ String name,
+ String migratedFromID
) {
if (error == null) {
this.error = -1;
@@ -47,6 +49,7 @@ public class GetDocResult extends Result {
this.versionID = versionID;
this.createdAt = createdAt;
this.user = new WLUser(name, email);
+ this.migratedFromID = migratedFromID;
}
@Override
@@ -59,6 +62,9 @@ public class GetDocResult extends Result {
latestVerBy.addProperty("email", getEmail());
latestVerBy.addProperty("name", getName());
jsonThis.add("latestVerBy", latestVerBy);
+ if (migratedFromID != null) {
+ jsonThis.addProperty("migratedFromId", migratedFromID);
+ }
} else {
jsonThis.addProperty("status", error);
String message;
@@ -93,6 +99,11 @@ public class GetDocResult extends Result {
} else {
versionID = jsonObject.get("latestVerId").getAsInt();
createdAt = jsonObject.get("latestVerAt").getAsString();
+ if (jsonObject.has("migratedFromId")) {
+ migratedFromID = jsonObject.get("migratedFromId").getAsString();
+ } else {
+ migratedFromID = null;
+ }
String name = null;
String email = null;
JsonElement latestVerBy = jsonObject.get("latestVerBy");
@@ -126,4 +137,6 @@ public class GetDocResult extends Result {
return user.getEmail();
}
+ public String getMigratedFromID() { return migratedFromID; }
+
}
diff --git a/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/state/SnapshotAPIState.java b/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/state/SnapshotAPIState.java
index 02f8e19a8b..b3095874f9 100644
--- a/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/state/SnapshotAPIState.java
+++ b/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/state/SnapshotAPIState.java
@@ -48,7 +48,8 @@ public class SnapshotAPIState {
243,
"2014-11-30T18:40:58Z",
"jdleesmiller+1@gmail.com",
- "John+1"
+ "John+1",
+ null
)
);
diff --git a/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/state/SnapshotAPIStateBuilder.java b/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/state/SnapshotAPIStateBuilder.java
index 2204592ca7..179985f1ea 100644
--- a/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/state/SnapshotAPIStateBuilder.java
+++ b/services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/state/SnapshotAPIStateBuilder.java
@@ -83,6 +83,10 @@ public class SnapshotAPIStateBuilder {
String projectName,
JsonObject jsonGetDoc
) {
+ String migratedFromId = null;
+ if (jsonGetDoc.has("migratedFromId")) {
+ migratedFromId = jsonGetDoc.get("migratedFromId").getAsString();
+ }
getDoc.put(
projectName,
new GetDocResult(
@@ -90,7 +94,8 @@ public class SnapshotAPIStateBuilder {
jsonGetDoc.get("versionID").getAsInt(),
jsonGetDoc.get("createdAt").getAsString(),
jsonGetDoc.get("email").getAsString(),
- jsonGetDoc.get("name").getAsString()
+ jsonGetDoc.get("name").getAsString(),
+ migratedFromId
)
);
}
diff --git a/services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/application/WLGitBridgeIntegrationTest.java b/services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/application/WLGitBridgeIntegrationTest.java
index dba7989362..1c3f7f9950 100644
--- a/services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/application/WLGitBridgeIntegrationTest.java
+++ b/services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/application/WLGitBridgeIntegrationTest.java
@@ -117,6 +117,12 @@ public class WLGitBridgeIntegrationTest {
put("pushSubmoduleFailsWithInvalidGitRepo", new HashMap() {{
put("state", new SnapshotAPIStateBuilder(getResourceAsStream("/pushSubmoduleFailsWithInvalidGitRepo/state/state.json")).build());
}});
+ put("canMigrateRepository", new HashMap() {{
+ put("state", new SnapshotAPIStateBuilder(getResourceAsStream("/canMigrateRepository/state/state.json")).build());
+ }});
+ put("skipMigrationWhenMigratedFromMissing", new HashMap() {{
+ put("state", new SnapshotAPIStateBuilder(getResourceAsStream("/skipMigrationWhenMigratedFromMissing/state/state.json")).build());
+ }});
}};
@Rule
@@ -787,6 +793,43 @@ public class WLGitBridgeIntegrationTest {
assertNotEquals(0, gitProcess.waitFor());
}
+ @Test
+ public void canMigrateRepository() throws IOException, GitAPIException, InterruptedException {
+ int gitBridgePort = 33881;
+ int mockServerPort = 3881;
+ MockSnapshotServer server = new MockSnapshotServer(mockServerPort, getResource("/canMigrateRepository").toFile());
+ server.start();
+ server.setState(states.get("canMigrateRepository").get("state"));
+ GitBridgeApp wlgb = new GitBridgeApp(new String[] {
+ makeConfigFile(gitBridgePort, mockServerPort)
+ });
+ wlgb.run();
+ File testprojDir = gitClone("testproj", gitBridgePort, dir);
+ File testprojDir2 = gitClone("testproj2", gitBridgePort, dir);
+ wlgb.stop();
+
+ // Second project content is equal to content of the first
+ assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canMigrateRepository/state/testproj"), testprojDir2.toPath()));
+ }
+
+ @Test
+ public void skipMigrationWhenMigratedFromMissing() throws IOException, GitAPIException, InterruptedException {
+ int gitBridgePort = 33882;
+ int mockServerPort = 3882;
+ MockSnapshotServer server = new MockSnapshotServer(mockServerPort, getResource("/skipMigrationWhenMigratedFromMissing").toFile());
+ server.start();
+ server.setState(states.get("skipMigrationWhenMigratedFromMissing").get("state"));
+ GitBridgeApp wlgb = new GitBridgeApp(new String[] {
+ makeConfigFile(gitBridgePort, mockServerPort)
+ });
+ wlgb.run();
+ // don't clone the source project first
+ File testprojDir2 = gitClone("testproj2", gitBridgePort, dir);
+ wlgb.stop();
+
+ assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/skipMigrationWhenMigratedFromMissing/state/testproj2"), testprojDir2.toPath()));
+ }
+
private String makeConfigFile(
int port,
int apiPort
diff --git a/services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/bridge/BridgeTest.java b/services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/bridge/BridgeTest.java
index 4d6df351ea..79dc4327b6 100644
--- a/services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/bridge/BridgeTest.java
+++ b/services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/bridge/BridgeTest.java
@@ -14,6 +14,7 @@ import uk.ac.ic.wlgitbridge.bridge.snapshot.SnapshotApiFacade;
import uk.ac.ic.wlgitbridge.bridge.swap.job.SwapJob;
import uk.ac.ic.wlgitbridge.bridge.swap.store.SwapStore;
import uk.ac.ic.wlgitbridge.git.exception.GitUserException;
+import uk.ac.ic.wlgitbridge.snapshot.getdoc.GetDocResult;
import java.io.IOException;
import java.util.ArrayDeque;
@@ -91,6 +92,9 @@ public class BridgeTest {
when(repoStore.getExistingRepo("asdf")).thenReturn(repo);
when(dbStore.getProjectState("asdf")).thenReturn(ProjectState.PRESENT);
when(snapshotAPI.projectExists(Optional.empty(), "asdf")).thenReturn(true);
+ when(
+ snapshotAPI.getDoc(Optional.empty(), "asdf")
+ ).thenReturn(Optional.of(mock(GetDocResult.class)));
when(
snapshotAPI.getSnapshots(
any(),
diff --git a/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/canMigrateRepository/state/state.json b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/canMigrateRepository/state/state.json
new file mode 100644
index 0000000000..895cd6ea76
--- /dev/null
+++ b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/canMigrateRepository/state/state.json
@@ -0,0 +1,83 @@
+[
+ {
+ "project": "testproj2",
+ "getDoc": {
+ "versionID": 1,
+ "createdAt": "2014-11-30T18:40:58.123Z",
+ "email": "jdleesmiller+1@gmail.com",
+ "name": "John+1",
+ "migratedFromId": "testproj"
+ },
+ "getSavedVers": [],
+ "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:3857/state/testproj/min_mean_wait_evm_7_eps_150dpi.png",
+ "path": "min_mean_wait_evm_7_eps_150dpi.png"
+ }
+ ]
+ }
+ ],
+ "push": "success",
+ "postback": {
+ "type": "success",
+ "versionID": 2
+ }
+ },
+ {
+ "project": "testproj",
+ "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.333Z"
+ }
+ ],
+ "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:3857/state/testproj/min_mean_wait_evm_7_eps_150dpi.png",
+ "path": "min_mean_wait_evm_7_eps_150dpi.png"
+ }
+ ]
+ }
+ ],
+ "push": "success",
+ "postback": {
+ "type": "success",
+ "versionID": 2
+ }
+ }
+]
diff --git a/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/canMigrateRepository/state/testproj/foo/bar/test.tex b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/canMigrateRepository/state/testproj/foo/bar/test.tex
new file mode 100644
index 0000000000..046794f19a
--- /dev/null
+++ b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/canMigrateRepository/state/testproj/foo/bar/test.tex
@@ -0,0 +1 @@
+This text is from another file.
\ No newline at end of file
diff --git a/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/canMigrateRepository/state/testproj/main.tex b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/canMigrateRepository/state/testproj/main.tex
new file mode 100644
index 0000000000..d95f3ad14d
--- /dev/null
+++ b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/canMigrateRepository/state/testproj/main.tex
@@ -0,0 +1 @@
+content
diff --git a/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/canMigrateRepository/state/testproj/min_mean_wait_evm_7_eps_150dpi.png b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/canMigrateRepository/state/testproj/min_mean_wait_evm_7_eps_150dpi.png
new file mode 100644
index 0000000000..74e1fcd990
Binary files /dev/null and b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/canMigrateRepository/state/testproj/min_mean_wait_evm_7_eps_150dpi.png differ
diff --git a/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/skipMigrationWhenMigratedFromMissing/state/state.json b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/skipMigrationWhenMigratedFromMissing/state/state.json
new file mode 100644
index 0000000000..5e1f5efe80
--- /dev/null
+++ b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/skipMigrationWhenMigratedFromMissing/state/state.json
@@ -0,0 +1,39 @@
+[
+ {
+ "project": "testproj2",
+ "getDoc": {
+ "versionID": 1,
+ "createdAt": "2014-11-30T18:40:58.123Z",
+ "email": "jdleesmiller+1@gmail.com",
+ "name": "John+1",
+ "migratedFromId": "testprojthatdoesnotexist"
+ },
+ "getSavedVers": [],
+ "getForVers": [
+ {
+ "versionID": 1,
+ "srcs": [
+ {
+ "content": "two\n",
+ "path": "main.tex"
+ },
+ {
+ "content": "This text is from another file.",
+ "path": "foo/bar/test.tex"
+ }
+ ],
+ "atts": [
+ {
+ "url": "http://127.0.0.1:3857/state/testproj/min_mean_wait_evm_7_eps_150dpi.png",
+ "path": "min_mean_wait_evm_7_eps_150dpi.png"
+ }
+ ]
+ }
+ ],
+ "push": "success",
+ "postback": {
+ "type": "success",
+ "versionID": 2
+ }
+ }
+]
diff --git a/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/skipMigrationWhenMigratedFromMissing/state/testproj2/foo/bar/test.tex b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/skipMigrationWhenMigratedFromMissing/state/testproj2/foo/bar/test.tex
new file mode 100644
index 0000000000..046794f19a
--- /dev/null
+++ b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/skipMigrationWhenMigratedFromMissing/state/testproj2/foo/bar/test.tex
@@ -0,0 +1 @@
+This text is from another file.
\ No newline at end of file
diff --git a/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/skipMigrationWhenMigratedFromMissing/state/testproj2/main.tex b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/skipMigrationWhenMigratedFromMissing/state/testproj2/main.tex
new file mode 100644
index 0000000000..f719efd430
--- /dev/null
+++ b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/skipMigrationWhenMigratedFromMissing/state/testproj2/main.tex
@@ -0,0 +1 @@
+two
diff --git a/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/skipMigrationWhenMigratedFromMissing/state/testproj2/min_mean_wait_evm_7_eps_150dpi.png b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/skipMigrationWhenMigratedFromMissing/state/testproj2/min_mean_wait_evm_7_eps_150dpi.png
new file mode 100644
index 0000000000..74e1fcd990
Binary files /dev/null and b/services/git-bridge/src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest/skipMigrationWhenMigratedFromMissing/state/testproj2/min_mean_wait_evm_7_eps_150dpi.png differ