Change-Id: I6691b454404dd4db3c690ecfc7515de765bc2ef7 Signed-off-by: Martin Goellnitz <m.goellnitz@outlook.com> Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>tags/v4.5.0.201609210915-r
import org.eclipse.jgit.api.Git; | import org.eclipse.jgit.api.Git; | ||||
import org.eclipse.jgit.api.errors.AbortedByHookException; | import org.eclipse.jgit.api.errors.AbortedByHookException; | ||||
import org.eclipse.jgit.hooks.CommitMsgHook; | import org.eclipse.jgit.hooks.CommitMsgHook; | ||||
import org.eclipse.jgit.hooks.PostCommitHook; | |||||
import org.eclipse.jgit.hooks.PreCommitHook; | import org.eclipse.jgit.hooks.PreCommitHook; | ||||
import org.eclipse.jgit.junit.JGitTestUtil; | import org.eclipse.jgit.junit.JGitTestUtil; | ||||
import org.eclipse.jgit.junit.RepositoryTestCase; | import org.eclipse.jgit.junit.RepositoryTestCase; | ||||
FS.DETECTED.findHook(db, PreCommitHook.NAME)); | FS.DETECTED.findHook(db, PreCommitHook.NAME)); | ||||
} | } | ||||
@Test | |||||
public void testFindPostCommitHook() throws Exception { | |||||
assumeSupportedPlatform(); | |||||
assertNull("no hook should be installed", | |||||
FS.DETECTED.findHook(db, PostCommitHook.NAME)); | |||||
File hookFile = writeHookFile(PostCommitHook.NAME, | |||||
"#!/bin/bash\necho \"test $1 $2\""); | |||||
assertEquals("expected to find post-commit hook", hookFile, | |||||
FS.DETECTED.findHook(db, PostCommitHook.NAME)); | |||||
} | |||||
@Test | @Test | ||||
public void testFailedCommitMsgHookBlocksCommit() throws Exception { | public void testFailedCommitMsgHookBlocksCommit() throws Exception { | ||||
assumeSupportedPlatform(); | assumeSupportedPlatform(); | ||||
assertEquals("new message\n", revCommit.getFullMessage()); | assertEquals("new message\n", revCommit.getFullMessage()); | ||||
} | } | ||||
@Test | |||||
public void testPostCommitRunHook() throws Exception { | |||||
assumeSupportedPlatform(); | |||||
writeHookFile(PostCommitHook.NAME, | |||||
"#!/bin/sh\necho \"test $1 $2\"\nread INPUT\necho $INPUT\necho 1>&2 \"stderr\""); | |||||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||||
ByteArrayOutputStream err = new ByteArrayOutputStream(); | |||||
ProcessResult res = FS.DETECTED.runHookIfPresent(db, | |||||
PostCommitHook.NAME, | |||||
new String[] { | |||||
"arg1", "arg2" }, | |||||
new PrintStream(out), new PrintStream(err), "stdin"); | |||||
assertEquals("unexpected hook output", "test arg1 arg2\nstdin\n", | |||||
out.toString("UTF-8")); | |||||
assertEquals("unexpected output on stderr stream", "stderr\n", | |||||
err.toString("UTF-8")); | |||||
assertEquals("unexpected exit code", 0, res.getExitCode()); | |||||
assertEquals("unexpected process status", ProcessResult.Status.OK, | |||||
res.getStatus()); | |||||
} | |||||
@Test | |||||
public void testAllCommitHooks() throws Exception { | |||||
assumeSupportedPlatform(); | |||||
writeHookFile(PreCommitHook.NAME, | |||||
"#!/bin/sh\necho \"test pre-commit\"\n\necho 1>&2 \"stderr pre-commit\"\nexit 0"); | |||||
writeHookFile(CommitMsgHook.NAME, | |||||
"#!/bin/sh\necho \"test commit-msg $1\"\n\necho 1>&2 \"stderr commit-msg\"\nexit 0"); | |||||
writeHookFile(PostCommitHook.NAME, | |||||
"#!/bin/sh\necho \"test post-commit\"\necho 1>&2 \"stderr post-commit\"\nexit 0"); | |||||
Git git = Git.wrap(db); | |||||
String path = "a.txt"; | |||||
writeTrashFile(path, "content"); | |||||
git.add().addFilepattern(path).call(); | |||||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||||
try { | |||||
git.commit().setMessage("commit") | |||||
.setHookOutputStream(new PrintStream(out)).call(); | |||||
} catch (AbortedByHookException e) { | |||||
fail("unexpected hook failure"); | |||||
} | |||||
assertEquals("unexpected hook output", | |||||
"test pre-commit\ntest commit-msg .git/COMMIT_EDITMSG\ntest post-commit\n", | |||||
out.toString("UTF-8")); | |||||
} | |||||
@Test | @Test | ||||
public void testRunHook() throws Exception { | public void testRunHook() throws Exception { | ||||
assumeSupportedPlatform(); | assumeSupportedPlatform(); |
hunkHeaderDoesNotMatchBodyLineCountOf=Hunk header {0} does not match body line count of {1} | hunkHeaderDoesNotMatchBodyLineCountOf=Hunk header {0} does not match body line count of {1} | ||||
illegalArgumentNotA=Not {0} | illegalArgumentNotA=Not {0} | ||||
illegalCombinationOfArguments=The combination of arguments {0} and {1} is not allowed | illegalCombinationOfArguments=The combination of arguments {0} and {1} is not allowed | ||||
illegalHookName=Illegal hook name {0} | |||||
illegalPackingPhase=Illegal packing phase {0} | illegalPackingPhase=Illegal packing phase {0} | ||||
illegalStateExists=exists {0} | illegalStateExists=exists {0} | ||||
improperlyPaddedBase64Input=Improperly padded Base64 input. | improperlyPaddedBase64Input=Improperly padded Base64 input. |
import java.text.MessageFormat; | import java.text.MessageFormat; | ||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.Collections; | import java.util.Collections; | ||||
import java.util.HashMap; | |||||
import java.util.LinkedList; | import java.util.LinkedList; | ||||
import java.util.List; | import java.util.List; | ||||
import org.eclipse.jgit.dircache.DirCacheEntry; | import org.eclipse.jgit.dircache.DirCacheEntry; | ||||
import org.eclipse.jgit.dircache.DirCacheIterator; | import org.eclipse.jgit.dircache.DirCacheIterator; | ||||
import org.eclipse.jgit.errors.UnmergedPathException; | import org.eclipse.jgit.errors.UnmergedPathException; | ||||
import org.eclipse.jgit.hooks.CommitMsgHook; | |||||
import org.eclipse.jgit.hooks.Hooks; | import org.eclipse.jgit.hooks.Hooks; | ||||
import org.eclipse.jgit.hooks.PostCommitHook; | |||||
import org.eclipse.jgit.hooks.PreCommitHook; | |||||
import org.eclipse.jgit.internal.JGitText; | import org.eclipse.jgit.internal.JGitText; | ||||
import org.eclipse.jgit.lib.CommitBuilder; | import org.eclipse.jgit.lib.CommitBuilder; | ||||
import org.eclipse.jgit.lib.Constants; | import org.eclipse.jgit.lib.Constants; | ||||
*/ | */ | ||||
private boolean noVerify; | private boolean noVerify; | ||||
private PrintStream hookOutRedirect; | |||||
private HashMap<String, PrintStream> hookOutRedirect = new HashMap<>(3); | |||||
private Boolean allowEmpty; | private Boolean allowEmpty; | ||||
state.name())); | state.name())); | ||||
if (!noVerify) { | if (!noVerify) { | ||||
Hooks.preCommit(repo, hookOutRedirect).call(); | |||||
Hooks.preCommit(repo, hookOutRedirect.get(PreCommitHook.NAME)) | |||||
.call(); | |||||
} | } | ||||
processOptions(state, rw); | processOptions(state, rw); | ||||
} | } | ||||
if (!noVerify) { | if (!noVerify) { | ||||
message = Hooks.commitMsg(repo, hookOutRedirect) | |||||
message = Hooks | |||||
.commitMsg(repo, | |||||
hookOutRedirect.get(CommitMsgHook.NAME)) | |||||
.setCommitMessage(message).call(); | .setCommitMessage(message).call(); | ||||
} | } | ||||
repo.writeMergeCommitMsg(null); | repo.writeMergeCommitMsg(null); | ||||
repo.writeRevertHead(null); | repo.writeRevertHead(null); | ||||
} | } | ||||
Hooks.postCommit(repo, | |||||
hookOutRedirect.get(PostCommitHook.NAME)).call(); | |||||
return revCommit; | return revCommit; | ||||
} | } | ||||
case REJECTED: | case REJECTED: | ||||
} | } | ||||
/** | /** | ||||
* Set the output stream for hook scripts executed by this command. If not | |||||
* set it defaults to {@code System.out}. | |||||
* Set the output stream for all hook scripts executed by this command | |||||
* (pre-commit, commit-msg, post-commit). If not set it defaults to | |||||
* {@code System.out}. | |||||
* | * | ||||
* @param hookStdOut | * @param hookStdOut | ||||
* the output stream for hook scripts executed by this command | * the output stream for hook scripts executed by this command | ||||
* @since 3.7 | * @since 3.7 | ||||
*/ | */ | ||||
public CommitCommand setHookOutputStream(PrintStream hookStdOut) { | public CommitCommand setHookOutputStream(PrintStream hookStdOut) { | ||||
this.hookOutRedirect = hookStdOut; | |||||
setHookOutputStream(PreCommitHook.NAME, hookStdOut); | |||||
setHookOutputStream(CommitMsgHook.NAME, hookStdOut); | |||||
setHookOutputStream(PostCommitHook.NAME, hookStdOut); | |||||
return this; | |||||
} | |||||
/** | |||||
* Set the output stream for a selected hook script executed by this command | |||||
* (pre-commit, commit-msg, post-commit). If not set it defaults to | |||||
* {@code System.out}. | |||||
* | |||||
* @param hookName | |||||
* name of the hook to set the output stream for | |||||
* @param hookStdOut | |||||
* the output stream to use for the selected hook | |||||
* @return {@code this} | |||||
* @since 4.5 | |||||
*/ | |||||
public CommitCommand setHookOutputStream(String hookName, | |||||
PrintStream hookStdOut) { | |||||
if (!(PreCommitHook.NAME.equals(hookName) | |||||
|| CommitMsgHook.NAME.equals(hookName) | |||||
|| PostCommitHook.NAME.equals(hookName))) { | |||||
throw new IllegalArgumentException( | |||||
MessageFormat.format(JGitText.get().illegalHookName, | |||||
hookName)); | |||||
} | |||||
hookOutRedirect.put(hookName, hookStdOut); | |||||
return this; | return this; | ||||
} | } | ||||
} | } |
return new PreCommitHook(repo, outputStream); | return new PreCommitHook(repo, outputStream); | ||||
} | } | ||||
/** | |||||
* @param repo | |||||
* @param outputStream | |||||
* The output stream, or {@code null} to use {@code System.out} | |||||
* @return The post-commit hook for the given repository. | |||||
* @since 4.5 | |||||
*/ | |||||
public static PostCommitHook postCommit(Repository repo, | |||||
PrintStream outputStream) { | |||||
return new PostCommitHook(repo, outputStream); | |||||
} | |||||
/** | /** | ||||
* @param repo | * @param repo | ||||
* @param outputStream | * @param outputStream |
/* | |||||
* Copyright (C) 2015 Obeo. | |||||
* and other copyright owners as documented in the project's IP log. | |||||
* | |||||
* This program and the accompanying materials are made available | |||||
* under the terms of the Eclipse Distribution License v1.0 which | |||||
* accompanies this distribution, is reproduced below, and is | |||||
* available at http://www.eclipse.org/org/documents/edl-v10.php | |||||
* | |||||
* All rights reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or | |||||
* without modification, are permitted provided that the following | |||||
* conditions are met: | |||||
* | |||||
* - Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* | |||||
* - Redistributions in binary form must reproduce the above | |||||
* copyright notice, this list of conditions and the following | |||||
* disclaimer in the documentation and/or other materials provided | |||||
* with the distribution. | |||||
* | |||||
* - Neither the name of the Eclipse Foundation, Inc. nor the | |||||
* names of its contributors may be used to endorse or promote | |||||
* products derived from this software without specific prior | |||||
* written permission. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND | |||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, | |||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
*/ | |||||
package org.eclipse.jgit.hooks; | |||||
import java.io.IOException; | |||||
import java.io.PrintStream; | |||||
import org.eclipse.jgit.api.errors.AbortedByHookException; | |||||
import org.eclipse.jgit.lib.Repository; | |||||
/** | |||||
* The <code>post-commit</code> hook implementation. This hook is run after the | |||||
* commit was successfully executed. | |||||
* | |||||
* @since 4.5 | |||||
*/ | |||||
public class PostCommitHook extends GitHook<Void> { | |||||
/** The post-commit hook name. */ | |||||
public static final String NAME = "post-commit"; //$NON-NLS-1$ | |||||
/** | |||||
* @param repo | |||||
* The repository | |||||
* @param outputStream | |||||
* The output stream the hook must use. {@code null} is allowed, | |||||
* in which case the hook will use {@code System.out}. | |||||
*/ | |||||
protected PostCommitHook(Repository repo, PrintStream outputStream) { | |||||
super(repo, outputStream); | |||||
} | |||||
@Override | |||||
public Void call() throws IOException, AbortedByHookException { | |||||
doRun(); | |||||
return null; | |||||
} | |||||
@Override | |||||
public String getHookName() { | |||||
return NAME; | |||||
} | |||||
} |
/***/ public String hunkHeaderDoesNotMatchBodyLineCountOf; | /***/ public String hunkHeaderDoesNotMatchBodyLineCountOf; | ||||
/***/ public String illegalArgumentNotA; | /***/ public String illegalArgumentNotA; | ||||
/***/ public String illegalCombinationOfArguments; | /***/ public String illegalCombinationOfArguments; | ||||
/***/ public String illegalHookName; | |||||
/***/ public String illegalPackingPhase; | /***/ public String illegalPackingPhase; | ||||
/***/ public String illegalStateExists; | /***/ public String illegalStateExists; | ||||
/***/ public String improperlyPaddedBase64Input; | /***/ public String improperlyPaddedBase64Input; |