Skip to content
This repository was archived by the owner on Apr 5, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/main/java/jbyoshi/gitupdate/GitUpdate.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
public class GitUpdate {
private static final Set<File> updated = new HashSet<>();
private static final ImmutableList<Processor> processors = ImmutableList.of(new Fetch(), new FastForward(),
new Push());
new Rebase(), new Push());

public static void main(String[] args) {
Report rootReport = null;
Expand Down
76 changes: 63 additions & 13 deletions src/main/java/jbyoshi/gitupdate/processor/Push.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,19 @@
*/
package jbyoshi.gitupdate.processor;

import java.io.IOException;
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.*;
import java.util.stream.Collectors;

import org.eclipse.jgit.api.*;
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.TooLargePackException;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.*;
import org.eclipse.jgit.transport.*;

Expand All @@ -26,6 +36,12 @@
import jbyoshi.gitupdate.*;

public final class Push extends Processor {
private static final Map<Repository, Set<String>> forcePushBranches = new WeakHashMap<>();

static void forcePush(Repository repo, String branch) {
if (branch.startsWith(Constants.R_HEADS)) branch = branch.substring(Constants.R_HEADS.length());
forcePushBranches.computeIfAbsent(repo, k -> new HashSet<>()).add(branch);
}

@Override
public void registerTasks(Repository repo, Git git, Task root) throws Exception {
Expand All @@ -41,15 +57,15 @@ public void registerTasks(Repository repo, Git git, Task root) throws Exception
for (Map.Entry<String, Collection<String>> remote : branchList.asMap().entrySet()) {
me.newChild(remote.getKey(), report -> {
try {
process(repo, git, remote.getKey(), remote.getValue(), report);
process(repo, remote.getKey(), remote.getValue(), report);
} catch (Exception e) {
report.newErrorChild(e);
}
});
}
}

private static void process(Repository repo, Git git, String remote, Collection<String> branches,
private static void process(Repository repo, String remote, Collection<String> branches,
Report report) throws Exception {
// Figure out if anything needs to be pushed.
Map<String, ObjectId> oldIds = new HashMap<>();
Expand All @@ -69,21 +85,55 @@ private static void process(Repository repo, Git git, String remote, Collection<
return;
}

PushCommand push = git.push().setCredentialsProvider(Prompts.INSTANCE).setTimeout(5)
.setRemote(remote);
ArrayList<RefSpec> refSpecs = new ArrayList<>();
for (String branch : branches) {
push.add(Constants.R_HEADS + branch);
RefSpec spec = new RefSpec(Constants.R_HEADS + branch);
refSpecs.add(spec);
}
for (PushResult result : push.call()) {
for (RemoteRefUpdate update : result.getRemoteUpdates()) {
if (update.getStatus() == RemoteRefUpdate.Status.OK) {
String branchName = Utils.getShortBranch(update.getSrcRef());
ObjectId oldId = oldIds.get(branchName);
String old = oldId.equals(ObjectId.zeroId()) ? "new branch" : oldId.name();
report.newChild(branchName + ": " + old + " -> " + update.getNewObjectId().name())
.modified();

try {
final List<Transport> transports;
transports = Transport.openAll(repo, remote, Transport.Operation.PUSH);
for (final Transport transport : transports) {
transport.setCredentialsProvider(Prompts.INSTANCE);

List<RefSpec> fetchRefSpecs = new RemoteConfig(repo.getConfig(), remote).getFetchRefSpecs();
final List<RemoteRefUpdate> toPush = new ArrayList<>(
Transport.findRemoteRefUpdatesFor(repo, refSpecs, fetchRefSpecs));
for (int i = 0; i < toPush.size(); i++) {
final RemoteRefUpdate update = toPush.get(i);
if (update.isForceUpdate()) {
toPush.set(i, new RemoteRefUpdate(update, repo.resolve(
update.getTrackingRefUpdate().getLocalName())));
}
}

try {
PushResult result = transport.push(null, toPush, null);

for (RemoteRefUpdate update : result.getRemoteUpdates()) {
if (update.getStatus() == RemoteRefUpdate.Status.OK) {
String branchName = Utils.getShortBranch(update.getSrcRef());
ObjectId oldId = oldIds.get(branchName);
String old = oldId.equals(ObjectId.zeroId()) ? "new branch" : oldId.name();
report.newChild(branchName + ": " + old + " -> " + update.getNewObjectId().name())
.modified();
}
}
} catch (TooLargePackException e) {
throw new org.eclipse.jgit.api.errors.TooLargePackException(e.getMessage(), e);
} catch (TransportException e) {
throw new org.eclipse.jgit.api.errors.TransportException(e.getMessage(), e);
} finally {
transport.close();
}
}
} catch (URISyntaxException e) {
throw new InvalidRemoteException(MessageFormat.format(JGitText.get().invalidRemote, remote));
} catch (TransportException e) {
throw new org.eclipse.jgit.api.errors.TransportException(e.getMessage(), e);
} catch (IOException e) {
throw new JGitInternalException(JGitText.get().exceptionCaughtDuringExecutionOfPushCommand,e);
}
}

Expand Down
64 changes: 64 additions & 0 deletions src/main/java/jbyoshi/gitupdate/processor/Rebase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package jbyoshi.gitupdate.processor;

import java.io.*;

import org.eclipse.jgit.api.*;
import org.eclipse.jgit.api.errors.*;
import org.eclipse.jgit.lib.*;

import jbyoshi.gitupdate.*;

public final class Rebase extends BranchProcessor {

@Override
public void process(Repository repo, Git git, String branch, Ref ref, Report report)
throws IOException, GitAPIException {
String trackingBranch = new BranchConfig(repo.getConfig(), branch).getTrackingBranch();
if (trackingBranch == null) {
return;
}

Ref oldHead = repo.getRef(Constants.HEAD).getTarget();
if (!oldHead.equals(ref)) {
try {
git.checkout().setName(ref.getName()).setCreateBranch(false).call();
} catch (RefAlreadyExistsException e) {
throw new AssertionError(e);
} catch (RefNotFoundException e) {
throw new AssertionError(e);
} catch (InvalidRefNameException e) {
throw new AssertionError(e);
}
}

try {
RebaseResult result = git.rebase().setUpstream(trackingBranch).call();
switch (result.getStatus()) {
case STOPPED:
case CONFLICTS:
Report conflicts = report.newChild("Conflicts").error();
result.getConflicts().forEach(file -> conflicts.newChild(file).error());
git.rebase().setOperation(RebaseCommand.Operation.ABORT).call();
break;
case UP_TO_DATE:
break;
case OK:
Push.forcePush(repo, branch);
//$FALL-THROUGH$
default:
Report details = report.newChild(result.getStatus().toString());
if (result.getStatus().isSuccessful()) {
details.modified();
} else {
details.error();
}
break;
}
} catch (NoHeadException e) {
throw new AssertionError(e);
} finally {
git.checkout().setName(branch).call();
}
}

}