package com.atlassian.jgitflow.core;
import com.atlassian.jgitflow.core.exception.*;
import com.atlassian.jgitflow.core.util.GitHelper;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.FetchResult;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.util.StringUtils;
import static com.atlassian.jgitflow.core.util.Preconditions.checkState;
/**
* Start a feature.
* <p>
* This will create a new branch using the feature prefix and feature name from the tip of develop
* </p>
* <p>
* Examples (<code>flow</code> is a {@link JGitFlow} instance):
* <p>
* Start a feature:
*
* <pre>
* flow.featureStart("feature").call();
* </pre>
* <p>
* Perform a fetch of develop before branching
*
* <pre>
* flow.featureStart("feature").setFetchDevelop(true).call();
* </pre>
*/
public class FeatureStartCommand extends AbstractGitFlowCommand<Ref>
{
private final String branchName;
private boolean fetchDevelop;
/**
* Create a new feature start command instance.
* <p></p>
* An instance of this class is usually obtained by calling {@link JGitFlow#featureStart(String)}
* @param branchName The name of the feature
* @param git The git instance to use
* @param gfConfig The GitFlowConfiguration to use
*/
FeatureStartCommand(String branchName, Git git, GitFlowConfiguration gfConfig)
{
super(git,gfConfig);
checkState(!StringUtils.isEmptyOrNull(branchName));
this.branchName = branchName;
this.fetchDevelop = false;
}
/**
*
* @return A reference to the new feature branch
* @throws NotInitializedException
* @throws JGitFlowGitAPIException
* @throws LocalBranchExistsException
* @throws BranchOutOfDateException
* @throws JGitFlowIOException
*/
@Override
public Ref call() throws NotInitializedException, JGitFlowGitAPIException, LocalBranchExistsException, BranchOutOfDateException, JGitFlowIOException
{
//TODO: we should test for remote feature and pull it if it exists
final String prefixedBranchName = gfConfig.getPrefixValue(JGitFlowConstants.PREFIXES.FEATURE.configKey()) + branchName;
requireGitFlowInitialized();
requireLocalBranchAbsent(prefixedBranchName);
if(fetchDevelop)
{
RefSpec spec = new RefSpec("+" + Constants.R_HEADS + gfConfig.getDevelop() + ":" + Constants.R_REMOTES + "origin/" + gfConfig.getDevelop());
try
{
FetchResult result = git.fetch().setRefSpecs(spec).call();
}
catch (GitAPIException e)
{
throw new JGitFlowGitAPIException(e);
}
}
try
{
//ensure local develop isn't behind remote develop
if(GitHelper.remoteBranchExists(git,gfConfig.getDevelop()))
{
requireLocalBranchNotBehindRemote(gfConfig.getDevelop());
}
//go ahead and create the feature branch
RevCommit developCommit = GitHelper.getLatestCommit(git,gfConfig.getDevelop());
return git.checkout()
.setName(prefixedBranchName)
.setCreateBranch(true)
.setStartPoint(developCommit)
.call();
}
catch (GitAPIException e)
{
throw new JGitFlowGitAPIException(e);
}
}
/**
* Set whether to perform a git fetch of the remote develop branch before branching
* @param fetch
* <code>true</code> to do the fetch, <code>false</code>(default) otherwise
* @return {@code this}
*/
public FeatureStartCommand setFetchDevelop(boolean fetch)
{
this.fetchDevelop = fetch;
return this;
}
}