
org.kuali.maven.plugins.fusion.SplitMojo Maven / Gradle / Ivy
/**
*
*/
package org.kuali.maven.plugins.fusion;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Execute;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.eclipse.jgit.api.CommitCommand;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.kuali.maven.plugins.fusion.util.GitFusionUtils;
import org.kuali.student.git.model.GitRepositoryUtils;
import org.kuali.student.git.model.ExternalModuleUtils;
import org.kuali.student.git.model.ExternalModuleUtils.IBranchHeadProvider;
import org.kuali.student.git.model.branch.large.LargeBranchNameProviderMapImpl;
import org.kuali.student.git.model.ref.exception.BranchRefExistsException;
import org.kuali.student.git.model.ref.utils.GitRefUtils;
import org.kuali.student.git.model.tree.GitTreeNodeData;
import org.kuali.student.git.model.tree.utils.GitTreeProcessor;
import org.kuali.student.git.model.tree.utils.JGitTreeUtils;
import org.kuali.student.svn.model.ExternalModuleInfo;
/**
* @author ocleirig
*
*/
@Mojo(name = FusionMavenPluginConstants.SPLIT_MOJO)
@Execute(goal = FusionMavenPluginConstants.SPLIT_MOJO)
public class SplitMojo extends AbstractFusionMojo {
/*
* true or false and is used to determine if we should commit the current branch before performing the split operation.
*/
@Parameter(property = FusionMavenPluginConstants.COMMIT_BEFORE_SPLIT_PREFIX, defaultValue = FusionMavenPluginConstants.COMMIT_BEFORE_SPLIT_PREFIX_DEFAULT)
protected String commitBeforeSplit;
/*
* true of false and is used to determine if we should amend the previous commit vs creating a new commit. Only used when commitBeforeSplit is set.
*/
@Parameter(property = FusionMavenPluginConstants.AMEND_SPLIT_COMMIT_PREFIX, defaultValue = FusionMavenPluginConstants.AMEND_SPLIT_COMMIT_PREFIX_DEFAULT)
protected String amend;
/*
* Merge mode just creates the split branches
*
* tag mode creates tags based on the GAV of the top level modules.
*/
@Parameter(property = FusionMavenPluginConstants.SPLIT_STYLE_PREFIX)
protected SplitStyle splitStyle = FusionMavenPluginConstants.SPLIT_STYLE_PREFIX_DEFAULT;
@Parameter(property = FusionMavenPluginConstants.SPLIT_AGGREGATE_BRANCH_NAME_PREFIX)
protected String aggregateBranchName = FusionMavenPluginConstants.SPLIT_AGGREGATE_BRANCH_NAME_PREFIX_DEFAULT;
private GitTreeProcessor treeProcessor;
private POMUtils pomUtils;
private Repository repo;
/**
*
*/
public SplitMojo() {
}
private void createTag (String rootTagName, RevCommit commit, ObjectInserter objectInserter) throws IOException, MojoFailureException {
ObjectId tagId = GitRefUtils.insertTag(rootTagName, commit,
objectInserter);
if (tagId != null) {
// update the tag reference
// copied from JGit's TagCommand
Result updateResult = GitRefUtils.createTagReference(repo,
rootTagName, tagId);
if (updateResult != Result.NEW) {
throw new MojoFailureException(
"Problem creating tag reference for " + rootTagName
+ " result = " + updateResult);
}
} else {
throw new MojoFailureException("Failed to create tag : "
+ rootTagName + " to commit : " + commit);
}
}
/*
* (non-Javadoc)
*
* @see org.apache.maven.plugin.Mojo#execute()
*/
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
try {
/*
* Assume that we are running on the aggregate and that the
* configuration will tell us how to fuse with our modules.
*/
File baseDir = project.getBasedir();
/*
* Assume that the pom is located in the working copy of the git
* repository on the branch we want to fuse into
*/
repo = GitRepositoryUtils.buildFileRepository(baseDir,
false, false);
treeProcessor = new GitTreeProcessor(repo);
pomUtils = new POMUtils();
ObjectReader objectReader = repo.newObjectReader();
ObjectInserter objectInserter = repo.newObjectInserter();
RevWalk rw = new RevWalk(repo);
String currentBranchName = repo.getBranch();
Ref currentHead = repo.getRef(currentBranchName);
RevCommit previousCommit = rw.parseCommit(currentHead.getObjectId());
if (this.commitBeforeSplit != null && this.commitBeforeSplit.equals("true")) {
CommitCommand commitCommand = GitFusionUtils.commit(repo, previousCommit, "[fusion-maven-plugin] Commit Before Split", true);
RevCommit commit = commitCommand.call();
if (commit == null) {
objectReader.release();
objectInserter.release();
rw.release();
repo.close();
throw new MojoFailureException(
"Unable commit on current branch : " + currentBranchName);
}
currentHead = repo.getRef(currentBranchName);
}
RevCommit fusedCommit = rw.parseCommit(currentHead.getObjectId());
List externals = new ArrayList<>();
MapmoduleNameToMapping = new HashMap();
for (Mapping mapping : mappings) {
Ref branchHead = repo.getRef(getBranchName(mapping));
if (branchHead == null) {
objectReader.release();
objectInserter.release();
rw.release();
repo.close();
throw new MojoFailureException(
"Unable to find a branch head for : "
+ mapping.getBranchName());
}
ObjectId headCommitId = branchHead.getObjectId();
ExternalModuleInfo external = new ExternalModuleInfo(
mapping.getModule(), mapping.getBranchName(),
headCommitId);
externals.add(external);
moduleNameToMapping.put(mapping.getModule(), mapping);
}
Map splitTreeData = ExternalModuleUtils.splitFusedTree(objectReader, objectInserter, rw, fusedCommit.getId(), externals);
ObjectId aggregateTreeId = splitTreeData.remove("remainder");
SetbranchesCreatedSet = new HashSet<>();
Map branchNameToObjectIdMap = new HashMap<>();
for (Map.Entry entry : splitTreeData.entrySet()) {
String moduleName = entry.getKey();
ObjectId splitTreeId = entry.getValue();
Mapping mapping = moduleNameToMapping.get(moduleName);
String splitBranchName = "split_" + mapping.getBranchName();
branchesCreatedSet.add(splitBranchName);
Ref moduleBranchHead = repo.getRef(getBranchName(mapping));
RevCommit moduleBranchCommit = rw.parseCommit(moduleBranchHead.getObjectId());
if (this.splitStyle.equals(SplitStyle.MERGE)) {
Ref ref = createBranch(repo, objectInserter, moduleBranchCommit, moduleName, splitBranchName, splitTreeId);
getLog().info(String.format ("created %s at %s", splitBranchName, ref.getObjectId().toString()));
branchNameToObjectIdMap.put(mapping.getBranchName(), ref.getObjectId());
}
else if (this.splitStyle.equals(SplitStyle.TAG)) {
String tagName = getTagName (splitTreeId);
ObjectId commitId = createSplitCommit(moduleBranchCommit, moduleName, splitTreeId, objectInserter);
createTag(tagName, rw.parseCommit(commitId), objectInserter);
branchNameToObjectIdMap.put(mapping.getBranchName(), commitId);
}
else {
getLog().error("invalid splitStyle: " + splitStyle);
}
}
repo.getRefDatabase().refresh();
branchesCreatedSet.add("split_" + aggregateBranchName);
String fusionMavenPluginDataFileContent = createFusionMavenPluginDataFileString(repo, mappings, branchNameToObjectIdMap);
aggregateTreeId = JGitTreeUtils.createTree(JGitTreeUtils.insertBlob(objectReader, objectInserter, aggregateTreeId, "fusion-maven-plugin.dat", fusionMavenPluginDataFileContent), objectInserter);
Ref aggregateBranchHead = repo.getRef(aggregateBranchRefSpec + aggregateBranchName);
RevCommit aggregateBranchCommit = rw.parseCommit(aggregateBranchHead.getObjectId());
if (this.splitStyle.equals(SplitStyle.MERGE)) {
createBranch(repo, objectInserter, aggregateBranchCommit, "aggregate", "split_"+aggregateBranchName, aggregateTreeId);
getLog().info("Splitting Branch: " + currentBranchName);
getLog().info("Split Branches: " + StringUtils.join(branchesCreatedSet.iterator(), ", "));
}
else if (this.splitStyle.equals(SplitStyle.TAG)) {
String tagName = getTagName (aggregateTreeId);
ObjectId commitId = createSplitCommit(aggregateBranchCommit, "aggregate", aggregateTreeId, objectInserter);
createTag(tagName, rw.parseCommit(commitId), objectInserter);
}
else {
getLog().error("invalid splitStyle: " + splitStyle);
}
objectReader.release();
objectInserter.release();
rw.release();
repo.close();
} catch (Exception e) {
if (e instanceof MojoExecutionException)
throw (MojoExecutionException) e;
else if (e instanceof MojoFailureException)
throw (MojoFailureException) e;
else
throw new MojoExecutionException(
"SplitMojo failed unexpectantly: ", e);
}
}
private String getTagName(ObjectId splitTreeId) throws MissingObjectException, IncorrectObjectTypeException, CorruptObjectException, IOException, MojoFailureException {
GitTreeNodeData splitTree = treeProcessor.extractExistingTreeData(splitTreeId, "");
ObjectId pomBlobId = splitTree.find(repo, "pom.xml");
String pomFileContents = new String (treeProcessor.getBlob(pomBlobId).getBytes());
GAV moduleGav = pomUtils.getGAV(pomFileContents);
if (moduleGav.getVersion().contains("-SNAPSHOT")) {
throw new MojoFailureException("pom version of tree (" + splitTreeId.getName() + ") contains -SNAPSHOT ("+moduleGav.getVersion()+"). Tagging can only occur on non-snapshot versions.");
}
String pomVersionBasedTagName = MojoHelper.getInstance(this).getTagName(moduleGav);
return pomVersionBasedTagName;
}
private String createFusionMavenPluginDataFileString(Repository repo,
List mappings, final Map mappingModuleNameToCommitId) throws MojoFailureException, IOException {
return ExternalModuleUtils.createFusionMavenPluginDataFileString(0L, new IBranchHeadProvider() {
@Override
public ObjectId getBranchHeadObjectId(String branchName) {
/*
* Resolve through provided map.
*/
return mappingModuleNameToCommitId.get(branchName);
}
}, convertToExternalModules(repo, mappings, mappingModuleNameToCommitId), new LargeBranchNameProviderMapImpl());
}
private List convertToExternalModules(
Repository repo, List mappings, MapmappingModuleNameToCommitId) throws IOException, MojoFailureException {
List externals = new ArrayList<>(mappings.size());
for (Mapping mapping : mappings) {
ExternalModuleInfo external = new ExternalModuleInfo(mapping.getModule(), mapping.getBranchName());
ObjectId mappingObjectId = mappingModuleNameToCommitId.get(mapping.getBranchName());
if (mappingObjectId != null)
external.setBranchHeadId(mappingObjectId);
else {
throw new MojoFailureException("Failed to determine the branch head for branch: " + mapping.getBranchName());
}
externals.add(external);
}
return externals;
}
private ObjectId createSplitCommit (RevCommit fusedCommit, String moduleName, ObjectId treeId, ObjectInserter objectInserter) throws IOException {
Set parents = new HashSet<>();
parents.add(fusedCommit.getId());
ObjectId commitId = GitFusionUtils.commit(objectInserter, "jcaddel", "[email protected]", "Split out " + moduleName , treeId, parents);
return commitId;
}
private Ref createBranch(Repository repo, ObjectInserter objectInserter, RevCommit parentCommit, String moduleName, String branchName, ObjectId treeId) throws IOException, BranchRefExistsException {
ObjectId commitId = createSplitCommit(parentCommit, moduleName, treeId, objectInserter);
Ref branchRef = GitRefUtils.createBranch(repo, Constants.R_HEADS + branchName, commitId, true);
if (branchRef == null)
getLog().warn("Unable to set branch : " + branchName + " to the split tree with id : " + commitId);
return branchRef;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy