blob: 747393f1e0af086a534509444bd3256292c6ff77 [file] [log] [blame]
/*******************************************************************************
* Copyright (C) 2011, 2012 Robin Stocker <robin@nibor.org>
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.egit.core.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.egit.core.Activator;
import org.eclipse.egit.core.GitCorePreferences;
import org.eclipse.egit.core.GitProjectSetCapability;
import org.eclipse.egit.core.RepositoryCache;
import org.eclipse.egit.core.RepositoryUtil;
import org.eclipse.egit.core.op.ConnectProviderOperation;
import org.eclipse.egit.core.project.RepositoryMapping;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.util.FileUtils;
import org.eclipse.team.core.ProjectSetSerializationContext;
import org.eclipse.team.core.TeamException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class GitProjectSetCapabilityTest {
private GitProjectSetCapability capability;
private List<IProject> createdProjects = new ArrayList<>();
private List<File> pathsToClean = new ArrayList<>();
protected final static TestUtils testUtils = new TestUtils();
private static int testMethodNumber = 0;
// the temporary directory
private File testDirectory;
@Before
public void setUp() throws Exception {
shutDownRepositories();
capability = new GitProjectSetCapability();
initNewTestDirectory();
}
private void initNewTestDirectory() throws Exception {
testMethodNumber++;
// create standalone temporary directory
testDirectory = testUtils
.createTempDir("LocalRepositoriesTests" + testMethodNumber);
if (testDirectory.exists()) {
FileUtils.delete(testDirectory,
FileUtils.RECURSIVE | FileUtils.RETRY);
}
if (!testDirectory.exists()) {
FileUtils.mkdir(testDirectory, true);
}
// we don't want to clone into <user_home> but into our test directory
File repoRoot = new File(testDirectory, "RepositoryRoot");
if (!repoRoot.exists()) {
FileUtils.mkdir(repoRoot, true);
}
// make sure the default directory for Repos is not the user home
IEclipsePreferences p = InstanceScope.INSTANCE
.getNode(Activator.PLUGIN_ID);
p.put(GitCorePreferences.core_defaultRepositoryDir, repoRoot.getPath());
}
@After
public void tearDown() throws Exception {
ResourcesPlugin.getWorkspace().getRoot().delete(IResource.FORCE, null);
for (IProject project : createdProjects) {
if (project.exists()) {
project.delete(true, true, null);
}
}
for (File pathToClean : pathsToClean) {
if (pathToClean.exists()) {
FileUtils.delete(pathToClean,
FileUtils.RECURSIVE | FileUtils.RETRY);
}
}
shutDownRepositories();
}
protected static void shutDownRepositories() {
for (Repository repository : RepositoryCache.INSTANCE
.getAllRepositories()) {
repository.close();
}
RepositoryCache.INSTANCE.clear();
}
@Test
public void testExport() throws Exception {
IProject aProject = createProject("a");
File aRepo = createRepository(aProject.getLocation(), "http://example.org/repo-a", "master");
connectProject(aProject, aRepo);
IPath bPath = ResourcesPlugin.getWorkspace().getRoot().getLocation().append("b");
File bRepo = createRepository(bPath, "http://example.org/repo-b", "master");
IProject baProject = createProject(bPath, "ba");
IProject bbProject = createProject(bPath, "bb");
connectProject(baProject, bRepo);
connectProject(bbProject, bRepo);
pathsToClean.add(bPath.toFile());
IProject cProject = createProject("c");
File cRepo = createRepository(cProject.getLocation(), "http://example.org/repo-c", "stable");
connectProject(cProject, cRepo);
IProject[] projects = new IProject[] { aProject, baProject, bbProject, cProject };
String[] references = capability.asReference(
projects, new ProjectSetSerializationContext(), new NullProgressMonitor());
assertEquals(4, references.length);
assertEquals("1.0,http://example.org/repo-a,master,.", references[0]);
assertEquals("1.0,http://example.org/repo-b,master,ba", references[1]);
assertEquals("1.0,http://example.org/repo-b,master,bb", references[2]);
assertEquals("1.0,http://example.org/repo-c,stable,.", references[3]);
}
@Test
public void testImport() throws Exception {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IPath reposPath = new Path(testDirectory.getPath()).append("repos");
pathsToClean.add(reposPath.toFile());
IPath aPath = reposPath.append("a");
IProject aProject = createProject(reposPath, "a");
createRepository(aPath, "notused", "master");
aProject.delete(false, true, null);
IPath bPath = reposPath.append("b");
IProject baProject = createProject(bPath, "ba");
IProject bbProject = createProject(bPath, "bb");
createRepository(bPath, "notused", "master");
baProject.delete(false, true, null);
bbProject.delete(false, true, null);
IPath cPath = reposPath.append("c");
IProject cProject = createProject(reposPath, "c");
createRepository(cPath, "notused", "stable");
cProject.delete(false, true, null);
String aReference = "1.0," + aPath.toFile().toURI().toString() + ",master,.";
String baReference = "1.0," + bPath.toFile().toURI().toString() + ",master,ba";
String bbReference = "1.0," + bPath.toFile().toURI().toString() + ",master,bb";
String cReference = "1.0," + cPath.toFile().toURI().toString() + ",stable,.";
String[] references = new String[] { aReference, baReference, bbReference, cReference };
addToWorkspace(references);
pathsToClean.add(root.getLocation().append("b").toFile());
IProject aImported = root.getProject("a");
createdProjects.add(aImported);
assertTrue(aImported.exists());
assertNotNull(RepositoryMapping.getMapping(aImported));
IProject baImported = root.getProject("ba");
createdProjects.add(baImported);
assertTrue(baImported.exists());
assertEquals(new Path(RepositoryUtil.getDefaultRepositoryDir())
.append("b/ba"), baImported.getLocation());
assertNotNull(RepositoryMapping.getMapping(baImported));
IProject bbImported = root.getProject("bb");
createdProjects.add(bbImported);
assertTrue(bbImported.exists());
assertEquals(new Path(RepositoryUtil.getDefaultRepositoryDir())
.append("b/bb"), bbImported.getLocation());
assertNotNull(RepositoryMapping.getMapping(bbImported));
IProject cImported = root.getProject("c");
createdProjects.add(cImported);
assertTrue(cImported.exists());
RepositoryMapping cMapping = RepositoryMapping.getMapping(cImported);
assertNotNull(cMapping);
assertEquals("stable", cMapping.getRepository().getBranch());
}
@Test
public void testImportWithDifferentBranchesOfSameRepo() throws Exception {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IPath reposPath = new Path(testDirectory.getPath()).append("repos");
pathsToClean.add(reposPath.toFile());
IPath xPath = reposPath.append("x");
IProject xaProject = createProject(xPath, "xa");
IProject xbProject = createProject(xPath, "xb");
createRepository(xPath, "notused", "stable");
xaProject.delete(false, true, null);
xbProject.delete(false, true, null);
String xaMasterReference = "1.0," + xPath.toFile().toURI().toString() + ",master,xa";
String xbStableReference = "1.0," + xPath.toFile().toURI().toString() + ",stable,xb";
String[] references = new String[] { xaMasterReference, xbStableReference };
addToWorkspace(references);
pathsToClean.add(root.getLocation().append("x").toFile());
pathsToClean.add(root.getLocation().append("x_stable").toFile());
IProject xaImported = root.getProject("xa");
createdProjects.add(xaImported);
assertTrue(xaImported.exists());
assertEquals(new Path(RepositoryUtil.getDefaultRepositoryDir())
.append("x/xa"), xaImported.getLocation());
RepositoryMapping xaMapping = RepositoryMapping.getMapping(xaImported);
assertNotNull(xaMapping);
assertEquals("master", xaMapping.getRepository().getBranch());
IProject xbImported = root.getProject("xb");
createdProjects.add(xbImported);
assertTrue(xbImported.exists());
assertEquals(new Path(RepositoryUtil.getDefaultRepositoryDir())
.append("x_stable/xb"), xbImported.getLocation());
RepositoryMapping xbMapping = RepositoryMapping.getMapping(xbImported);
assertNotNull(xbMapping);
assertEquals("stable", xbMapping.getRepository().getBranch());
}
@Test
public void testImportWithMultipleCallsForSameDestinationRepo() throws Exception {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IPath reposPath = root.getLocation().append("repos");
pathsToClean.add(reposPath.toFile());
IPath xPath = reposPath.append("x");
IProject xaProject = createProject(xPath, "xa");
IProject xbProject = createProject(xPath, "xb");
String url = createUrl(xPath);
createRepository(xPath, url, "stable");
xaProject.delete(false, true, null);
xbProject.delete(false, true, null);
String xaReference = createProjectReference(xPath, "master", "xa");
String xbReference = createProjectReference(xPath, "master", "xb");
// This should work because there is not yet a repo at the destination
addToWorkspace(new String[] { xaReference });
// This should work because the repo that is already there is for the
// same remote URL. It's assumed to be ok and will skip cloning and
// directly import the project.
addToWorkspace(new String[] { xbReference });
pathsToClean.add(root.getLocation().append("x").toFile());
IPath otherPathWithX = reposPath.append("other").append("x");
String otherReferenceWithDifferentUrl = createProjectReference(otherPathWithX, "master", "xb");
try {
capability.addToWorkspace(new String[] { otherReferenceWithDifferentUrl },
new ProjectSetSerializationContext(),
new NullProgressMonitor());
fail("Should throw TeamException when a repo exists at the place but doesn't have the same URL.");
} catch (TeamException e) {
// This is expected
}
}
@Test
public void testImportWhereRepoAlreadyExistsAtDifferentLocation() throws Exception {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IPath reposPath = new Path(testDirectory.getPath()).append("repo");
pathsToClean.add(reposPath.toFile());
IPath repoPath = reposPath.append("existingbutdifferent");
IProject project = createProject(repoPath, "project");
project.delete(false, true, null);
String url = createUrl(repoPath);
File repoDir = createRepository(repoPath, url, "master");
IPath otherRepoPath = reposPath.append("other");
File otherRepoDir = createRepository(otherRepoPath, "other-url", "master");
RepositoryUtil.INSTANCE.addConfiguredRepository(repoDir);
RepositoryUtil.INSTANCE.addConfiguredRepository(otherRepoDir);
String reference = createProjectReference(repoPath, "master", "project");
addToWorkspace(new String[] { reference });
IProject imported = root.getProject("project");
assertEquals("Expected imported project to be from already existing repository",
reposPath.append("existingbutdifferent/project")
.toOSString(),
imported.getLocation().toOSString());
}
@Test
public void testImportFromRepoWithUrlOnlyDifferingInUserName()
throws Exception {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IPath reposPath = root.getLocation().append("repos");
pathsToClean.add(reposPath.toFile());
IPath repoPath = reposPath.append("repo");
IProject project = createProject(repoPath, "project");
project.delete(false, true, null);
String url = createUrl(repoPath, "ssh", "userName");
File repoDir = createRepository(repoPath, url, "master");
RepositoryUtil.INSTANCE.addConfiguredRepository(repoDir);
String reference = createProjectReference(repoPath, "ssh", /* no user */
null, "master", "project");
addToWorkspace(new String[] { reference });
IProject imported = root.getProject("project");
assertEquals(
"Expected imported project to be from already existing repository. User name must be ignored in URL.",
root.getLocation().append("repos/repo/project"),
imported.getLocation());
}
private IProject createProject(String name) throws CoreException {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IProject p = root.getProject(name);
p.create(null);
p.open(null);
createdProjects.add(p);
return p;
}
private IProject createProject(IPath parentLocation, String name) throws CoreException {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IProject p = root.getProject(name);
IProjectDescription projectDescription = ResourcesPlugin.getWorkspace().newProjectDescription(p.getName());
projectDescription.setLocation(parentLocation.append(name));
p.create(projectDescription, null);
p.open(null);
createdProjects.add(p);
return p;
}
private File createRepository(IPath location, String url, String branch) throws Exception {
File gitDirectory = new File(location.toFile(), Constants.DOT_GIT);
Repository repo = FileRepositoryBuilder.create(gitDirectory);
repo.getConfig().setString(ConfigConstants.CONFIG_REMOTE_SECTION, "origin", ConfigConstants.CONFIG_KEY_URL, url);
repo.getConfig().setString(ConfigConstants.CONFIG_BRANCH_SECTION, branch, ConfigConstants.CONFIG_KEY_REMOTE, "origin");
repo.create();
repo.close();
try (Git git = new Git(repo)) {
git.add().addFilepattern(".").call();
git.commit().setMessage("initial").call();
if (!branch.equals("master")) {
git.checkout().setName(branch).setCreateBranch(true).call();
}
}
pathsToClean.add(gitDirectory);
return gitDirectory;
}
private void connectProject(IProject project, File gitDir) throws CoreException {
ConnectProviderOperation operation = new ConnectProviderOperation(
project.getProject(), gitDir);
operation.execute(null);
}
private static String createProjectReference(IPath repoPath, String branch, String projectPath) {
return "1.0," + createUrl(repoPath) + "," + branch + "," + projectPath;
}
private static String createProjectReference(IPath repoPath,
String protocol, String user, String branch, String projectPath)
throws Exception {
return "1.0," + createUrl(repoPath, protocol, user) + "," + branch
+ "," + projectPath;
}
private static String createUrl(IPath repoPath) {
return repoPath.toFile().toURI().toString();
}
private static String createUrl(IPath repoPath, String protocol, String user)
throws URISyntaxException {
URI uri = new URI(protocol, user, "localhost", 42, repoPath
.setDevice(null).makeAbsolute().toString(), null, null);
return uri.toString();
}
private void addToWorkspace(String[] references) throws TeamException {
capability.addToWorkspace(references,
new ProjectSetSerializationContext(),
new NullProgressMonitor());
}
}