package ut.com.atlassian.jgitflow.core;
import java.io.File;
import com.atlassian.jgitflow.core.JGitFlow;
import com.atlassian.jgitflow.core.JGitFlowConstants;
import com.atlassian.jgitflow.core.JGitFlowInitCommand;
import com.atlassian.jgitflow.core.exception.BranchOutOfDateException;
import com.atlassian.jgitflow.core.exception.DirtyWorkingTreeException;
import com.atlassian.jgitflow.core.exception.MergeConflictsNotResolvedException;
import com.atlassian.jgitflow.core.util.FileHelper;
import com.atlassian.jgitflow.core.util.GitHelper;
import org.apache.commons.io.FileUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Test;
import ut.com.atlassian.jgitflow.core.testutils.RepoUtil;
import static org.junit.Assert.*;
/**
* @since version
*/
public class FeatureFinishTest extends BaseGitFlowTest
{
@Test
public void finishFeature() throws Exception
{
Git git = RepoUtil.createRepositoryWithMasterAndDevelop(newDir());
JGitFlowInitCommand initCommand = new JGitFlowInitCommand();
JGitFlow flow = initCommand.setDirectory(git.getRepository().getWorkTree()).call();
flow.featureStart("my-feature").call();
//just in case
assertEquals(flow.getFeatureBranchPrefix() + "my-feature", git.getRepository().getBranch());
flow.featureFinish("my-feature").call();
//we should be on develop branch
assertEquals(flow.getDevelopBranchName(), git.getRepository().getBranch());
//feature branch should be gone
Ref ref2check = git.getRepository().getRef(flow.getFeatureBranchPrefix() + "my-feature");
assertNull(ref2check);
}
@Test(expected = DirtyWorkingTreeException.class)
public void finishFeatureWithUnStagedFile() throws Exception
{
Git git = RepoUtil.createRepositoryWithMasterAndDevelop(newDir());
JGitFlowInitCommand initCommand = new JGitFlowInitCommand();
JGitFlow flow = initCommand.setDirectory(git.getRepository().getWorkTree()).call();
flow.featureStart("my-feature").call();
//create a new file
File junkFile = new File(git.getRepository().getWorkTree(), "junk.txt");
FileUtils.writeStringToFile(junkFile, "I am junk");
//try to finish
flow.featureFinish("my-feature").call();
}
@Test(expected = DirtyWorkingTreeException.class)
public void finishFeatureUnCommittedFile() throws Exception
{
Git git = RepoUtil.createRepositoryWithMasterAndDevelop(newDir());
JGitFlowInitCommand initCommand = new JGitFlowInitCommand();
JGitFlow flow = initCommand.setDirectory(git.getRepository().getWorkTree()).call();
flow.featureStart("my-feature").call();
//create a new file and add it to the index
File junkFile = new File(git.getRepository().getWorkTree(), "junk.txt");
FileUtils.writeStringToFile(junkFile, "I am junk");
git.add().addFilepattern(junkFile.getName()).call();
//try to finish
flow.featureFinish("my-feature").call();
}
@Test
public void finishFeatureWithNewCommit() throws Exception
{
Git git = RepoUtil.createRepositoryWithMasterAndDevelop(newDir());
JGitFlowInitCommand initCommand = new JGitFlowInitCommand();
JGitFlow flow = initCommand.setDirectory(git.getRepository().getWorkTree()).call();
flow.featureStart("my-feature").call();
//create a new commit
File junkFile = new File(git.getRepository().getWorkTree(), "junk.txt");
FileUtils.writeStringToFile(junkFile, "I am junk");
git.add().addFilepattern(junkFile.getName()).call();
RevCommit commit = git.commit().setMessage("committing junk file").call();
//make sure develop doesn't report our commit yet
assertFalse(GitHelper.isMergedInto(git, commit, flow.getDevelopBranchName()));
//try to finish
flow.featureFinish("my-feature").call();
//we should be on develop branch
assertEquals(flow.getDevelopBranchName(), git.getRepository().getBranch());
//feature branch should be gone
Ref ref2check = git.getRepository().getRef(flow.getFeatureBranchPrefix() + "my-feature");
assertNull(ref2check);
//the develop branch should have our commit
assertTrue(GitHelper.isMergedInto(git, commit, flow.getDevelopBranchName()));
//since fast-forward is not suppressed the latest commit should not be a merge commit
assertEquals(1, GitHelper.getLatestCommit(git, flow.getDevelopBranchName()).getParentCount());
}
@Test
public void finishFeatureWithNewCommitAndSuppressFastForward() throws Exception
{
Git git = RepoUtil.createRepositoryWithMasterAndDevelop(newDir());
JGitFlowInitCommand initCommand = new JGitFlowInitCommand();
JGitFlow flow = initCommand.setDirectory(git.getRepository().getWorkTree()).call();
flow.featureStart("my-feature").call();
//create a new commit
File junkFile = new File(git.getRepository().getWorkTree(), "junk.txt");
FileUtils.writeStringToFile(junkFile, "I am junk");
git.add().addFilepattern(junkFile.getName()).call();
RevCommit commit = git.commit().setMessage("committing junk file").call();
//make sure develop doesn't report our commit yet
assertFalse(GitHelper.isMergedInto(git, commit, flow.getDevelopBranchName()));
//try to finish
flow.featureFinish("my-feature").setSuppressFastForward(true).call();
//we should be on develop branch
assertEquals(flow.getDevelopBranchName(), git.getRepository().getBranch());
//the develop branch should have our commit
assertTrue(GitHelper.isMergedInto(git, commit, flow.getDevelopBranchName()));
//since fast-forward is suppressed the latest commit should be a merge commit with 2 parents
assertEquals(2, GitHelper.getLatestCommit(git, flow.getDevelopBranchName()).getParentCount());
}
@Test
public void finishFeatureKeepBranch() throws Exception
{
Git git = RepoUtil.createRepositoryWithMasterAndDevelop(newDir());
JGitFlowInitCommand initCommand = new JGitFlowInitCommand();
JGitFlow flow = initCommand.setDirectory(git.getRepository().getWorkTree()).call();
flow.featureStart("my-feature").call();
//just in case
assertEquals(flow.getFeatureBranchPrefix() + "my-feature", git.getRepository().getBranch());
flow.featureFinish("my-feature").setKeepBranch(true).call();
//we should be on develop branch
assertEquals(flow.getDevelopBranchName(), git.getRepository().getBranch());
//feature branch should still exist
Ref ref2check = git.getRepository().getRef(flow.getFeatureBranchPrefix() + "my-feature");
assertNotNull(ref2check);
}
@Test
public void finishFeatureWithMultipleCommits() throws Exception
{
Git git = RepoUtil.createRepositoryWithMasterAndDevelop(newDir());
JGitFlowInitCommand initCommand = new JGitFlowInitCommand();
JGitFlow flow = initCommand.setDirectory(git.getRepository().getWorkTree()).call();
flow.featureStart("my-feature").call();
//create a new commit
File junkFile = new File(git.getRepository().getWorkTree(), "junk.txt");
FileUtils.writeStringToFile(junkFile, "I am junk");
git.add().addFilepattern(junkFile.getName()).call();
RevCommit commit = git.commit().setMessage("committing junk file").call();
//create second commit
File junkFile2 = new File(git.getRepository().getWorkTree(), "junk2.txt");
FileUtils.writeStringToFile(junkFile2, "I am junk, and so are you");
git.add().addFilepattern(junkFile2.getName()).call();
RevCommit commit2 = git.commit().setMessage("updating junk file").call();
//make sure develop doesn't have our commits yet
assertFalse(GitHelper.isMergedInto(git, commit, flow.getDevelopBranchName()));
assertFalse(GitHelper.isMergedInto(git, commit2, flow.getDevelopBranchName()));
//try to finish
flow.featureFinish("my-feature").call();
//we should be on develop branch
assertEquals(flow.getDevelopBranchName(), git.getRepository().getBranch());
//feature branch should be gone
Ref ref2check = git.getRepository().getRef(flow.getFeatureBranchPrefix() + "my-feature");
assertNull(ref2check);
//the develop branch should have both of our commits now
assertTrue(GitHelper.isMergedInto(git, commit, flow.getDevelopBranchName()));
assertTrue(GitHelper.isMergedInto(git, commit2, flow.getDevelopBranchName()));
}
@Test
public void finishFeatureWithSquash() throws Exception
{
Git git = RepoUtil.createRepositoryWithMasterAndDevelop(newDir());
JGitFlowInitCommand initCommand = new JGitFlowInitCommand();
JGitFlow flow = initCommand.setDirectory(git.getRepository().getWorkTree()).call();
flow.featureStart("my-feature").call();
//create a new commit
File junkFile = new File(git.getRepository().getWorkTree(), "junk.txt");
FileUtils.writeStringToFile(junkFile, "I am junk");
git.add().addFilepattern(junkFile.getName()).call();
RevCommit commit = git.commit().setMessage("committing junk file").call();
//create second commit
File junkFile2 = new File(git.getRepository().getWorkTree(), "junk2.txt");
FileUtils.writeStringToFile(junkFile2, "I am junk, and so are you");
git.add().addFilepattern(junkFile2.getName()).call();
RevCommit commit2 = git.commit().setMessage("updating junk file").call();
//make sure develop doesn't have our commits yet
assertFalse(GitHelper.isMergedInto(git, commit, flow.getDevelopBranchName()));
assertFalse(GitHelper.isMergedInto(git, commit2, flow.getDevelopBranchName()));
//try to finish
flow.featureFinish("my-feature").setSquash(true).call();
//we should be on develop branch
assertEquals(flow.getDevelopBranchName(), git.getRepository().getBranch());
//feature branch should be gone
Ref ref2check = git.getRepository().getRef(flow.getFeatureBranchPrefix() + "my-feature");
assertNull(ref2check);
//the develop branch should NOT have both of our commits now
assertFalse(GitHelper.isMergedInto(git, commit, flow.getDevelopBranchName()));
assertFalse(GitHelper.isMergedInto(git, commit2, flow.getDevelopBranchName()));
//we should have the feature files
File developJunk = new File(git.getRepository().getWorkTree(), "junk.txt");
File developJunk2 = new File(git.getRepository().getWorkTree(), "junk2.txt");
assertTrue(developJunk.exists());
assertTrue(developJunk2.exists());
}
@Test(expected = BranchOutOfDateException.class)
public void finishFeatureBehindRemoteWithFetch() throws Exception
{
Git git = null;
Git remoteGit = null;
remoteGit = RepoUtil.createRepositoryWithBranches(newDir(), "develop", "feature/my-feature");
git = Git.cloneRepository().setDirectory(newDir()).setURI("file://" + remoteGit.getRepository().getWorkTree().getPath()).call();
JGitFlowInitCommand initCommand = new JGitFlowInitCommand();
JGitFlow flow = initCommand.setDirectory(git.getRepository().getWorkTree()).call();
flow.featureStart("my-feature").call();
//do a commit to the remote feature branch
remoteGit.checkout().setName(flow.getFeatureBranchPrefix() + "my-feature").call();
File junkFile = new File(remoteGit.getRepository().getWorkTree(), "junk.txt");
FileUtils.writeStringToFile(junkFile, "I am junk");
remoteGit.add().addFilepattern(junkFile.getName()).call();
remoteGit.commit().setMessage("adding junk file").call();
flow.featureFinish("my-feature").setFetch(true).call();
}
@Test
public void finishFeatureWithRebase() throws Exception
{
Git git = null;
Git remoteGit = null;
remoteGit = RepoUtil.createRepositoryWithBranches(newDir(), "develop", "feature/my-feature");
git = Git.cloneRepository().setDirectory(newDir()).setURI("file://" + remoteGit.getRepository().getWorkTree().getPath()).call();
JGitFlowInitCommand initCommand = new JGitFlowInitCommand();
JGitFlow flow = initCommand.setDirectory(git.getRepository().getWorkTree()).call();
flow.featureStart("my-feature").call();
git.pull().call();
//do a commit to the develop branch
git.checkout().setName(flow.getDevelopBranchName()).call();
File junkFile = new File(git.getRepository().getWorkTree(), "junk.txt");
FileUtils.writeStringToFile(junkFile, "I am junk");
git.add().addFilepattern(junkFile.getName()).call();
git.commit().setMessage("adding junk file").call();
flow.featureFinish("my-feature").setRebase(true).call();
}
@Test(expected = MergeConflictsNotResolvedException.class)
public void finishFeatureMergeConflict() throws Exception
{
Git git = RepoUtil.createRepositoryWithMasterAndDevelop(newDir());
JGitFlowInitCommand initCommand = new JGitFlowInitCommand();
JGitFlow flow = initCommand.setDirectory(git.getRepository().getWorkTree()).call();
flow.featureStart("my-feature").call();
//go back to develop and do a commit
git.checkout().setName(flow.getDevelopBranchName()).call();
File junkFile = new File(git.getRepository().getWorkTree(), "junk.txt");
FileUtils.writeStringToFile(junkFile, "A");
git.add().addFilepattern(junkFile.getName()).call();
git.commit().setMessage("committing junk file").call();
//commit the same file in feature to create a conflict
git.checkout().setName(flow.getFeatureBranchPrefix() + "my-feature").call();
FileUtils.writeStringToFile(junkFile, "B");
git.add().addFilepattern(junkFile.getName()).call();
git.commit().setMessage("committing junk file").call();
//try to finish
try
{
flow.featureFinish("my-feature").setKeepBranch(true).call();
}
catch (Exception e)
{
File gitFlowDir = new File(git.getRepository().getDirectory(), JGitFlowConstants.GITFLOW_DIR);
File mergeBase = new File(gitFlowDir, JGitFlowConstants.MERGE_BASE);
assertTrue(mergeBase.exists());
assertEquals(flow.getDevelopBranchName(), FileHelper.readFirstLine(mergeBase));
throw e;
}
}
@Test
public void finishFeatureConflictRestore() throws Exception
{
Git git = RepoUtil.createRepositoryWithMasterAndDevelop(newDir());
JGitFlowInitCommand initCommand = new JGitFlowInitCommand();
JGitFlow flow = initCommand.setDirectory(git.getRepository().getWorkTree()).call();
flow.featureStart("my-feature").call();
//go back to develop and do a commit
git.checkout().setName(flow.getDevelopBranchName()).call();
File junkFile = new File(git.getRepository().getWorkTree(), "junk.txt");
FileUtils.writeStringToFile(junkFile, "A");
git.add().addFilepattern(junkFile.getName()).call();
git.commit().setMessage("committing junk file").call();
//commit the same file in feature to create a conflict
git.checkout().setName(flow.getFeatureBranchPrefix() + "my-feature").call();
FileUtils.writeStringToFile(junkFile, "B");
git.add().addFilepattern(junkFile.getName()).call();
git.commit().setMessage("committing junk file").call();
boolean gotException = false;
//try to finish
try
{
flow.featureFinish("my-feature").call();
}
catch (Exception e)
{
gotException = true;
File gitFlowDir = new File(git.getRepository().getDirectory(), JGitFlowConstants.GITFLOW_DIR);
File mergeBase = new File(gitFlowDir, JGitFlowConstants.MERGE_BASE);
assertTrue(mergeBase.exists());
assertEquals(flow.getDevelopBranchName(), FileHelper.readFirstLine(mergeBase));
}
if (!gotException)
{
fail("Merge Conflict not detected!!");
}
assertEquals(flow.getDevelopBranchName(), git.getRepository().getBranch());
FileUtils.writeStringToFile(junkFile, "A");
git.add().addFilepattern(junkFile.getName()).setUpdate(true).call();
git.commit().setMessage("merging").call();
//try to finish again
git.checkout().setName(flow.getFeatureBranchPrefix() + "my-feature").call();
flow.featureFinish("my-feature").call();
//we should be on develop branch
assertEquals(flow.getDevelopBranchName(), git.getRepository().getBranch());
//feature branch should be gone
Ref ref2check = git.getRepository().getRef(flow.getFeatureBranchPrefix() + "my-feature");
assertNull(ref2check);
File gitFlowDir2 = new File(git.getRepository().getDirectory(), JGitFlowConstants.GITFLOW_DIR);
File mergeBase2 = new File(gitFlowDir2, JGitFlowConstants.MERGE_BASE);
assertFalse(mergeBase2.exists());
}
}