import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
+import org.eclipse.jgit.api.errors.AbortedByHookException;
import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.TransportException;
+import org.eclipse.jgit.hooks.PrePushHook;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.TextProgressMonitor;
import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
+import org.eclipse.jgit.util.io.NullOutputStream;
import org.junit.Before;
import org.junit.Test;
.fromString("0000000000000000000000000000000000000001"));
final Ref ref = new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, "refs/heads/master",
ObjectId.fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
- testOneUpdateStatus(rru, ref, Status.REJECTED_REMOTE_CHANGED, null);
+ try (ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ PrintStream out = new PrintStream(bytes, true,
+ StandardCharsets.UTF_8);
+ PrintStream err = new PrintStream(NullOutputStream.INSTANCE)) {
+ MockPrePushHook hook = new MockPrePushHook(db, out, err);
+ testOneUpdateStatus(rru, ref, Status.REJECTED_REMOTE_CHANGED, null,
+ hook);
+ out.flush();
+ String result = new String(bytes.toString(StandardCharsets.UTF_8));
+ assertEquals("", result);
+ }
}
/**
refUpdates.add(rruOk);
refUpdates.add(rruReject);
advertisedRefs.add(refToChange);
- executePush();
- assertEquals(Status.OK, rruOk.getStatus());
- assertTrue(rruOk.isFastForward());
- assertEquals(Status.NON_EXISTING, rruReject.getStatus());
+ try (ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ PrintStream out = new PrintStream(bytes, true,
+ StandardCharsets.UTF_8);
+ PrintStream err = new PrintStream(NullOutputStream.INSTANCE)) {
+ MockPrePushHook hook = new MockPrePushHook(db, out, err);
+ executePush(hook);
+ assertEquals(Status.OK, rruOk.getStatus());
+ assertTrue(rruOk.isFastForward());
+ assertEquals(Status.NON_EXISTING, rruReject.getStatus());
+ out.flush();
+ String result = new String(bytes.toString(StandardCharsets.UTF_8));
+ assertEquals(
+ "null 0000000000000000000000000000000000000000 "
+ + "refs/heads/master 2c349335b7f797072cf729c4f3bb0914ecb6dec9\n",
+ result);
+ }
}
/**
final Ref advertisedRef, final Status expectedStatus,
Boolean fastForward) throws NotSupportedException,
TransportException {
+ return testOneUpdateStatus(rru, advertisedRef, expectedStatus,
+ fastForward, null);
+ }
+
+ private PushResult testOneUpdateStatus(final RemoteRefUpdate rru,
+ final Ref advertisedRef, final Status expectedStatus,
+ Boolean fastForward, PrePushHook hook)
+ throws NotSupportedException, TransportException {
refUpdates.add(rru);
if (advertisedRef != null)
advertisedRefs.add(advertisedRef);
- final PushResult result = executePush();
+ final PushResult result = executePush(hook);
assertEquals(expectedStatus, rru.getStatus());
if (fastForward != null)
assertEquals(fastForward, Boolean.valueOf(rru.isFastForward()));
private PushResult executePush() throws NotSupportedException,
TransportException {
- process = new PushProcess(transport, refUpdates);
+ return executePush(null);
+ }
+
+ private PushResult executePush(PrePushHook hook)
+ throws NotSupportedException, TransportException {
+ process = new PushProcess(transport, refUpdates, hook);
return process.execute(new TextProgressMonitor());
}
}
}
}
+
+ private static class MockPrePushHook extends PrePushHook {
+
+ private final PrintStream output;
+
+ public MockPrePushHook(Repository repo, PrintStream out,
+ PrintStream err) {
+ super(repo, out, err);
+ output = out;
+ }
+
+ @Override
+ protected void doRun() throws AbortedByHookException, IOException {
+ output.print(getStdinArgs());
+ }
+ }
}
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
+import org.eclipse.jgit.api.errors.AbortedByHookException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.TransportException;
+import org.eclipse.jgit.hooks.PrePushHook;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ProgressMonitor;
/** A list of option strings associated with this push */
private List<String> pushOptions;
+ private final PrePushHook prePush;
+
/**
* Create process for specified transport and refs updates specification.
*
* connection.
* @param toPush
* specification of refs updates (and local tracking branches).
- *
+ * @param prePush
+ * {@link PrePushHook} to run after the remote advertisement has
+ * been gotten
* @throws TransportException
*/
PushProcess(final Transport transport,
- final Collection<RemoteRefUpdate> toPush) throws TransportException {
- this(transport, toPush, null);
+ final Collection<RemoteRefUpdate> toPush, PrePushHook prePush)
+ throws TransportException {
+ this(transport, toPush, prePush, null);
}
/**
* connection.
* @param toPush
* specification of refs updates (and local tracking branches).
+ * @param prePush
+ * {@link PrePushHook} to run after the remote advertisement has
+ * been gotten
* @param out
* OutputStream to write messages to
* @throws TransportException
*/
PushProcess(final Transport transport,
- final Collection<RemoteRefUpdate> toPush, OutputStream out)
- throws TransportException {
+ final Collection<RemoteRefUpdate> toPush, PrePushHook prePush,
+ OutputStream out) throws TransportException {
this.walker = new RevWalk(transport.local);
this.transport = transport;
this.toPush = new LinkedHashMap<>();
+ this.prePush = prePush;
this.out = out;
this.pushOptions = transport.getPushOptions();
for (RemoteRefUpdate rru : toPush) {
monitor.endTask();
final Map<String, RemoteRefUpdate> preprocessed = prepareRemoteUpdates();
+ List<RemoteRefUpdate> willBeAttempted = preprocessed.values()
+ .stream().filter(u -> {
+ switch (u.getStatus()) {
+ case NON_EXISTING:
+ case REJECTED_NODELETE:
+ case REJECTED_NONFASTFORWARD:
+ case REJECTED_OTHER_REASON:
+ case REJECTED_REMOTE_CHANGED:
+ case UP_TO_DATE:
+ return false;
+ default:
+ return true;
+ }
+ }).collect(Collectors.toList());
+ if (!willBeAttempted.isEmpty()) {
+ if (prePush != null) {
+ try {
+ prePush.setRefs(willBeAttempted);
+ prePush.call();
+ } catch (AbortedByHookException | IOException e) {
+ throw new TransportException(e.getMessage(), e);
+ }
+ }
+ }
if (transport.isDryRun())
modifyUpdatesForDryRun();
else if (!preprocessed.isEmpty())