package org.jfrog.bamboo.release.vcs.git;
import com.google.common.collect.Lists;
import org.eclipse.jgit.api.PushCommand;
import org.eclipse.jgit.api.errors.InvalidRemoteException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.*;
import java.io.IOException;
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* A class used to execute a {@code Push} command. It has setters for all supported options and arguments of this
* command and a {@link #call()} method to finally execute the command.
* <p/>
* This class is receiving its own custom {@link Transport} in order to execute the command, it is configured by the SSH
* key-pair and pass-phrase that is sent from Bamboo.
*/
public class SshPushCommand extends PushCommand {
private final Transport transport;
private List<RefSpec> refSpecs;
private ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
/**
* @param repo
*/
protected SshPushCommand(Repository repo, Transport transport) {
super(repo);
this.transport = transport;
refSpecs = Lists.newArrayListWithCapacity(3);
}
/**
* Executes the {@code push} command with all the options and parameters collected by the setter methods of this
* class. Each instance of this class should only be used for one invocation of the command (means: one call to
* {@link #call()})
*
* @return an iteration over {@link PushResult} objects
* @throws InvalidRemoteException when called with an invalid remote uri
* @throws JGitInternalException a low-level exception of JGit has occurred. The original exception can be
* retrieved by calling {@link Exception#getCause()}.
*/
@Override
public Iterable<PushResult> call() throws JGitInternalException,
InvalidRemoteException {
checkCallable();
List<PushResult> pushResults = Lists.newArrayListWithCapacity(3);
try {
if (isForce()) {
final List<RefSpec> orig = new ArrayList<RefSpec>(refSpecs);
refSpecs.clear();
for (final RefSpec spec : orig) {
refSpecs.add(spec.setForceUpdate(true));
}
}
final RemoteConfig cfg = new RemoteConfig(repo.getConfig(), getRemote());
transport.applyConfig(cfg);
if (0 <= getTimeout()) {
transport.setTimeout(getTimeout());
}
transport.setPushThin(isThin());
if (getReceivePack() != null) {
transport.setOptionReceivePack(getReceivePack());
}
transport.setDryRun(isDryRun());
final Collection<RemoteRefUpdate> toPush = transport
.findRemoteRefUpdatesFor(getRefSpecs());
transport.push(monitor, toPush);
try {
PushResult result = transport.push(monitor, toPush);
pushResults.add(result);
} catch (TransportException e) {
throw new JGitInternalException(
JGitText.get().exceptionCaughtDuringExecutionOfPushCommand,
e);
} finally {
transport.close();
}
} catch (URISyntaxException e) {
throw new InvalidRemoteException(MessageFormat.format(JGitText.get().invalidRemote, getRemote()));
} catch (NotSupportedException e) {
throw new JGitInternalException(JGitText.get().exceptionCaughtDuringExecutionOfPushCommand, e);
} catch (IOException e) {
throw new JGitInternalException(JGitText.get().exceptionCaughtDuringExecutionOfPushCommand, e);
}
return pushResults;
}
}