package ut.com.atlassian.maven.plugins.jgitflow.manager;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.SecureRandom;
import java.util.*;
import com.atlassian.jgitflow.core.JGitFlow;
import com.atlassian.maven.plugins.jgitflow.ReleaseContext;
import com.atlassian.maven.plugins.jgitflow.helper.SessionAndProjects;
import com.atlassian.maven.plugins.jgitflow.manager.FlowReleaseManager;
import com.google.common.base.Strings;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.manager.WagonManager;
import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.DefaultArtifactRepository;
import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
import org.apache.maven.artifact.resolver.ArtifactCollector;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
import org.apache.maven.artifact.versioning.VersionRange;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.DependencyManagement;
import org.apache.maven.model.Profile;
import org.apache.maven.model.Repository;
import org.apache.maven.profiles.DefaultProfileManager;
import org.apache.maven.profiles.ProfileManager;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectBuilder;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.maven.project.ProjectSorter;
import org.apache.maven.settings.Settings;
import org.apache.maven.shared.release.util.ReleaseUtil;
import org.codehaus.plexus.PlexusJUnit4TestCase;
import org.codehaus.plexus.context.ContextException;
import org.codehaus.plexus.context.DefaultContext;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.StringUtils;
import org.junit.After;
import org.junit.Before;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @since version
*/
public abstract class AbstractFlowManagerTest extends PlexusJUnit4TestCase
{
protected MavenProjectBuilder projectBuilder;
protected ArtifactRepository localRepository;
protected File testFileBase;
private static final SecureRandom random = new SecureRandom();
public static final String PROJECT_BASEDIR = "";
private static final DefaultContext EMPTY_CONTEXT = new DefaultContext()
{
public Object get(Object key) throws ContextException
{
return null;
}
};
@Before
public void doSetup() throws Exception
{
projectBuilder = (MavenProjectBuilder) lookup(MavenProjectBuilder.ROLE);
ArtifactRepositoryLayout layout = (ArtifactRepositoryLayout) lookup(ArtifactRepositoryLayout.ROLE, "default");
String localRepoPath = getTestFile(PROJECT_BASEDIR + "target/local-repository").getAbsolutePath().replace('\\', '/');
localRepository = new DefaultArtifactRepository("local", "file://" + localRepoPath, layout);
this.testFileBase = newTempDir();
}
@After
public void doTearDown() throws Exception
{
((Contextualizable) projectBuilder).contextualize(EMPTY_CONTEXT);
((Contextualizable) lookup(WagonManager.ROLE)).contextualize(EMPTY_CONTEXT);
// if(null != testFileBase && testFileBase.exists())
// {
// try
// {
// FileUtils.deleteDirectory(testFileBase);
// }
// catch (IOException e)
// {
// //ignore
// }
// }
}
@Override
protected InputStream getCustomConfiguration() throws Exception
{
String configBase = System.getProperty("basedir", "");
if (!configBase.endsWith("/"))
{
configBase = configBase + "/";
}
return org.apache.commons.io.FileUtils.openInputStream(new File(configBase + "target/components.xml"));
}
protected SessionAndProjects basicReleaseRewriteTest(String projectName) throws Exception
{
return basicReleaseRewriteTest(projectName, "");
}
protected SessionAndProjects basicReleaseRewriteTest(String projectName, String releaseVersion) throws Exception
{
List<MavenProject> projects = createReactorProjects("rewrite-for-release", projectName);
File projectRoot = projects.get(0).getBasedir();
ReleaseContext ctx = new ReleaseContext(projectRoot);
if (!Strings.isNullOrEmpty(releaseVersion))
{
ctx.setDefaultReleaseVersion(releaseVersion);
}
ctx.setInteractive(false).setNoTag(true);
return basicReleaseRewriteTest(projectName, ctx);
}
protected SessionAndProjects basicReleaseRewriteTest(String projectName, ReleaseContext ctx) throws Exception
{
List<MavenProject> projects = createReactorProjects("rewrite-for-release", projectName);
File projectRoot = ctx.getBaseDir();
JGitFlow flow = JGitFlow.getOrInit(projectRoot);
flow.git().checkout().setName(flow.getDevelopBranchName()).call();
assertOnDevelop(flow);
initialCommitAll(flow);
FlowReleaseManager relman = getReleaseManager();
MavenSession session = new MavenSession(getContainer(), new Settings(), localRepository, null, null, null, projectRoot.getAbsolutePath(), new Properties(), new Properties(), null);
relman.start(ctx, projects, session);
assertOnRelease(flow, ctx.getDefaultReleaseVersion());
compareSnapPomFiles(projects);
assertTrue(flow.git().status().call().isClean());
flow.git().checkout().setName(flow.getDevelopBranchName()).call();
compareDevPomFiles(projects);
return new SessionAndProjects(session, projects);
}
protected void basicHotfixRewriteTest(String projectName) throws Exception
{
basicHotfixRewriteTest(projectName, "");
}
protected void basicHotfixRewriteTest(String projectName, String releaseVersion) throws Exception
{
List<MavenProject> projects = createReactorProjects("rewrite-for-hotfix", projectName);
File projectRoot = projects.get(0).getBasedir();
ReleaseContext ctx = new ReleaseContext(projectRoot);
if (!Strings.isNullOrEmpty(releaseVersion))
{
ctx.setDefaultReleaseVersion(releaseVersion);
}
ctx.setInteractive(false).setNoTag(true);
basicHotfixRewriteTest(projectName, ctx);
}
protected void basicHotfixRewriteTest(String projectName, ReleaseContext ctx) throws Exception
{
List<MavenProject> projects = createReactorProjects("rewrite-for-hotfix", projectName);
File projectRoot = ctx.getBaseDir();
JGitFlow flow = JGitFlow.getOrInit(projectRoot);
flow.git().checkout().setName(flow.getMasterBranchName()).call();
assertOnMaster(flow);
initialCommitAll(flow);
FlowReleaseManager relman = getHotfixManager();
MavenSession session = new MavenSession(getContainer(), new Settings(), localRepository, null, null, null, projectRoot.getAbsolutePath(), new Properties(), new Properties(), null);
ctx.setInteractive(false);
relman.start(ctx, projects, session);
assertOnHotfix(flow);
compareSnapPomFiles(projects);
assertTrue(flow.git().status().call().isClean());
}
protected void initialCommitAll(JGitFlow flow) throws Exception
{
commitAll(flow, "Initial commit");
}
protected void commitAll(JGitFlow flow, String message) throws Exception
{
flow.git().add().addFilepattern(".").call();
flow.git().commit().setMessage(message).call();
}
protected void assertOnDevelop(JGitFlow flow) throws Exception
{
assertEquals(flow.getDevelopBranchName(), flow.git().getRepository().getBranch());
}
protected void assertOnMaster(JGitFlow flow) throws Exception
{
assertEquals(flow.getMasterBranchName(), flow.git().getRepository().getBranch());
}
protected void assertOnRelease(JGitFlow flow, String version) throws Exception
{
if (Strings.isNullOrEmpty(version))
{
assertTrue(flow.git().getRepository().getBranch().startsWith(flow.getReleaseBranchPrefix()));
}
else
{
assertEquals(flow.getReleaseBranchPrefix() + version, flow.git().getRepository().getBranch());
}
}
protected void assertOnFeature(JGitFlow flow, String feature) throws Exception
{
if (Strings.isNullOrEmpty(feature))
{
assertTrue(flow.git().getRepository().getBranch().startsWith(flow.getFeatureBranchPrefix()));
}
else
{
assertEquals(flow.getFeatureBranchPrefix() + feature, flow.git().getRepository().getBranch());
}
}
protected void assertOnHotfix(JGitFlow flow) throws Exception
{
assertTrue(flow.git().getRepository().getBranch().contains(flow.getHotfixBranchPrefix()));
}
protected FlowReleaseManager getReleaseManager() throws Exception
{
return (FlowReleaseManager) lookup(FlowReleaseManager.class.getName(), "release");
}
protected FlowReleaseManager getHotfixManager() throws Exception
{
return (FlowReleaseManager) lookup(FlowReleaseManager.class.getName(), "hotfix");
}
protected FlowReleaseManager getFeatureManager() throws Exception
{
return (FlowReleaseManager) lookup(FlowReleaseManager.class.getName(), "feature");
}
protected String readTestProjectFile(String fileName) throws IOException
{
return ReleaseUtil.readXmlFile(getTestFile(PROJECT_BASEDIR + "target/test-classes/projects/" + fileName));
}
protected void copyTestProject(String path, String subpath) throws IOException
{
File testResourcesDir = getTestFile(PROJECT_BASEDIR + "src/test/resources/");
File resourceDir = null;
File targetDir = null;
if (Strings.isNullOrEmpty(subpath))
{
resourceDir = new File(testResourcesDir, "projects/" + path + "/");
targetDir = new File(testFileBase, "projects/" + path + "/");
}
else
{
resourceDir = new File(testResourcesDir, "projects/" + path + "/" + subpath + "/");
targetDir = new File(testFileBase, "projects/" + path + "/" + subpath + "/");
}
FileUtils.copyDirectoryStructure(resourceDir, targetDir);
}
protected List<MavenProject> createReactorProjects(String path, String subpath) throws Exception
{
return createReactorProjects(path, path, subpath, true);
}
protected List<MavenProject> createReactorProjects(String path, String subpath, boolean clean) throws Exception
{
return createReactorProjects(path, path, subpath, clean);
}
protected List<MavenProject> createReactorProjectsNoClean(String path, String subpath) throws Exception
{
return createReactorProjects(path, path, subpath, false);
}
protected List<MavenProject> createReactorProjects(String path, String targetPath, String subpath, boolean clean)
throws Exception
{
File testFile = null;
if (Strings.isNullOrEmpty(subpath))
{
testFile = new File(testFileBase, "projects/" + path + "/pom.xml");
}
else
{
testFile = new File(testFileBase, "projects/" + path + "/" + subpath + "/pom.xml");
}
Stack<File> projectFiles = new Stack<File>();
projectFiles.push(testFile);
List<DefaultArtifactRepository> repos =
Collections.singletonList(new DefaultArtifactRepository("central", getRemoteRepositoryURL(), new DefaultRepositoryLayout()));
Repository repository = new Repository();
repository.setId("central");
repository.setUrl(getRemoteRepositoryURL());
ProfileManager profileManager = new DefaultProfileManager(getContainer());
Profile profile = new Profile();
profile.setId("profile");
profile.addRepository(repository);
profileManager.addProfile(profile);
profileManager.activateAsDefault(profile.getId());
List<MavenProject> reactorProjects = new ArrayList<MavenProject>();
String cleaned = "";
while (!projectFiles.isEmpty())
{
File file = (File) projectFiles.pop();
// Recopy the test resources since they are modified in some tests
//FileUtils.copyDirectory(srcDir,file.getParentFile());
String filePath = file.getPath();
int index = filePath.indexOf("projects");
filePath = filePath.substring(index).replace('\\', '/');
File newFile = new File(testFileBase, StringUtils.replace(filePath, path, targetPath));
if (clean && !cleaned.equals(newFile.getParentFile().getName()))
{
//clean the parent dir
newFile.mkdirs();
FileUtils.cleanDirectory(newFile.getParentFile());
File srcDir = new File(getTestFile(PROJECT_BASEDIR + "src/test/resources/"), filePath).getParentFile();
FileUtils.copyDirectoryStructure(srcDir, newFile.getParentFile());
cleaned = newFile.getParentFile().getName();
}
MavenProject project = projectBuilder.build(newFile, localRepository, profileManager);
for (Iterator i = project.getModules().iterator(); i.hasNext(); )
{
String module = (String) i.next();
File moduleFile = new File(file.getParentFile(), module);
if (moduleFile.isFile())
{
projectFiles.push(moduleFile);
}
else
{
projectFiles.push(new File(moduleFile, "/pom.xml"));
}
}
reactorProjects.add(project);
}
ProjectSorter sorter = new ProjectSorter(reactorProjects);
reactorProjects = sorter.getSortedProjects();
ArtifactFactory artifactFactory = (ArtifactFactory) lookup(ArtifactFactory.ROLE);
ArtifactCollector artifactCollector = (ArtifactCollector) lookup(ArtifactCollector.class.getName());
ArtifactMetadataSource artifactMetadataSource = (ArtifactMetadataSource) lookup(ArtifactMetadataSource.ROLE);
// pass back over and resolve dependencies - can't be done earlier as the order may not be correct
for (Iterator i = reactorProjects.iterator(); i.hasNext(); )
{
MavenProject project = (MavenProject) i.next();
project.setRemoteArtifactRepositories(repos);
project.setPluginArtifactRepositories(repos);
Artifact projectArtifact = project.getArtifact();
Map managedVersions = createManagedVersionMap(
ArtifactUtils.versionlessKey(projectArtifact.getGroupId(), projectArtifact.getArtifactId()),
project.getDependencyManagement(), artifactFactory);
project.setDependencyArtifacts(project.createArtifacts(artifactFactory, null, null));
ArtifactResolutionResult result = artifactCollector.collect(project.getDependencyArtifacts(),
projectArtifact, managedVersions,
localRepository, repos, artifactMetadataSource,
null, Collections.EMPTY_LIST);
project.setArtifacts(result.getArtifacts());
}
return reactorProjects;
}
private Map<String, Artifact> createManagedVersionMap(String projectId, DependencyManagement dependencyManagement, ArtifactFactory artifactFactory) throws ProjectBuildingException
{
Map<String, Artifact> map;
if (dependencyManagement != null && dependencyManagement.getDependencies() != null)
{
map = new HashMap<String, Artifact>();
for (Iterator i = dependencyManagement.getDependencies().iterator(); i.hasNext(); )
{
Dependency d = (Dependency) i.next();
try
{
VersionRange versionRange = VersionRange.createFromVersionSpec(d.getVersion());
Artifact artifact = artifactFactory.createDependencyArtifact(d.getGroupId(), d.getArtifactId(),
versionRange, d.getType(),
d.getClassifier(), d.getScope());
map.put(d.getManagementKey(), artifact);
}
catch (InvalidVersionSpecificationException e)
{
throw new ProjectBuildingException(projectId, "Unable to parse version '" + d.getVersion() +
"' for dependency '" + d.getManagementKey() + "': " + e.getMessage(), e);
}
}
}
else
{
map = Collections.emptyMap();
}
return map;
}
private String getRemoteRepositoryURL() throws IOException
{
File testFile = getTestFile(PROJECT_BASEDIR + "src/test/remote-repository");
if (testFile.getAbsolutePath().equals(testFile.getCanonicalPath()))
{
return "file://" + getTestFile(PROJECT_BASEDIR + "src/test/remote-repository").getAbsolutePath().replace('\\', '/');
}
return "file://" + getTestFile(PROJECT_BASEDIR + "src/test/remote-repository").getCanonicalPath().replace('\\', '/');
}
protected void comparePomFiles(List<MavenProject> reactorProjects) throws IOException
{
for (MavenProject project : reactorProjects)
{
comparePomFiles(project);
}
}
protected void compareDevPomFiles(List<MavenProject> reactorProjects) throws IOException
{
for (MavenProject project : reactorProjects)
{
compareDevPomFiles(project);
}
}
protected void compareSnapPomFiles(List<MavenProject> reactorProjects) throws IOException
{
for (MavenProject project : reactorProjects)
{
compareSnapPomFiles(project);
}
}
protected void comparePomFiles(MavenProject project) throws IOException
{
File actualFile = project.getFile();
File expectedFile = new File(actualFile.getParentFile(), "expected-nosnap-" + actualFile.getName());
comparePomFiles(expectedFile, actualFile);
}
protected void compareDevPomFiles(MavenProject project) throws IOException
{
File actualFile = project.getFile();
File expectedFile = new File(actualFile.getParentFile(), "expected-dev-" + actualFile.getName());
comparePomFiles(expectedFile, actualFile);
}
protected void compareSnapPomFiles(MavenProject project) throws IOException
{
File actualFile = project.getFile();
File expectedFile = new File(actualFile.getParentFile(), "expected-snap-" + actualFile.getName());
comparePomFiles(expectedFile, actualFile);
}
protected void comparePomFiles(File expectedFile, File actualFile) throws IOException
{
String expectedPom = ReleaseUtil.readXmlFile(expectedFile);
String actualPom = ReleaseUtil.readXmlFile(actualFile);
assertEquals(expectedPom, actualPom);
}
public void updatePomVersion(File pomFile, String oldVersion, String newVersion) throws IOException
{
String xmlString = org.apache.commons.io.FileUtils.readFileToString(pomFile);
String updatedXml = org.apache.commons.lang.StringUtils.replace(xmlString, "<version>" + oldVersion + "</version>", "<version>" + newVersion + "</version>");
org.apache.commons.io.FileUtils.writeStringToFile(pomFile, updatedXml);
}
public File newTempDir()
{
File baseDir = new File(System.getProperty("java.io.tmpdir"));
String name = randomName("mvngf-");
File tmp = new File(baseDir, name);
tmp.mkdirs();
return tmp;
}
public File newDir(String name)
{
return new File(testFileBase, name);
}
public File newDir()
{
return newDir(randomName("mvngftest"));
}
private String randomName(String base)
{
long n = random.nextLong();
n = (n == Long.MIN_VALUE) ? 0 : Math.abs(n);
return base + Long.toString(n);
}
}