# HG changeset patch # User Dmitry Neverov # Date 1329408870 -14400 # Node ID 88480a85f888fd309c8b3ac666749899d46de034 # Parent 62f273711a49c7cba55dd3af99dba4ea715d79e8# Parent 00d13c910f5dea33a80a0602898ba76f06804473 Some exit codes mean errors diff -r 62f273711a49 -r 88480a85f888 mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandResult.java --- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandResult.java Wed Feb 15 18:18:11 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandResult.java Thu Feb 16 20:14:30 2012 +0400 @@ -8,9 +8,11 @@ import org.jetbrains.annotations.Nullable; import java.util.Collections; +import java.util.HashSet; import java.util.Set; import static com.intellij.openapi.util.text.StringUtil.isEmpty; +import static java.util.Arrays.asList; import static jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandUtil.removePrivateData; /** @@ -20,6 +22,14 @@ */ public class CommandResult { + //Mercurial returns -1 in the case of errors (see dispatch.py) + //and on some shells (e.g. windows cmd) it is truncated to 255. + //A non-zero exit code is not always an error: + //http://mercurial.selenic.com/bts/issue186 + //http://mercurial.selenic.com/bts/issue2189 + //e.g. pull command in hg 2.1 exits with 1 if no new changes were pulled. + private static final Set ERROR_EXIT_CODES = setOf(-1, 255); + private final Logger myLogger; private final String myCommand; private final ExecResult myDelegate; @@ -82,11 +92,12 @@ } private boolean isFailure() { - //A non-zero exit code is not an error: - //http://mercurial.selenic.com/bts/issue186 - //http://mercurial.selenic.com/bts/issue2189 - //E.g. pull command in hg 2.1 exits with 1 if no new changes were pulled - return getException() != null; + return getException() != null || isErrorExitCode(); + } + + private boolean isErrorExitCode() { + int exitCode = myDelegate.getExitCode(); + return ERROR_EXIT_CODES.contains(exitCode); } private boolean shouldDetectErrors() { @@ -161,4 +172,8 @@ } } } + + private static Set setOf(Integer... ints) { + return new HashSet(asList(ints)); + } } diff -r 62f273711a49 -r 88480a85f888 mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandResultTest.java --- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandResultTest.java Wed Feb 15 18:18:11 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandResultTest.java Thu Feb 16 20:14:30 2012 +0400 @@ -8,6 +8,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.io.ByteArrayInputStream; @@ -38,6 +39,25 @@ myLogger.assertLogMessagesDontContain(password); } + @DataProvider(name = "exitCodesForErrors") + public static Object[][] exitCodesForErrors() { + return new Object[][] { + new Object[] { -1 }, + new Object[] { 255}}; + } + + @Test(expectedExceptions = VcsException.class, + dataProvider = "exitCodesForErrors") + public void should_detect_error_for_exit_code(int exitCode) throws VcsException { + CommandResult commandResult = commandResultFor(execResult().withExitCode(exitCode)); + commandResult.checkCommandFailed(); + } + + public void exit_code_of_one_is_not_an_error() throws VcsException { + CommandResult commandResult = commandResultFor(execResult().withStdout("pull: no new changes").withExitCode(1)); + commandResult.checkCommandFailed(); + } + @Test(expectedExceptions = UnrelatedRepositoryException.class) public void should_detect_unrelated_repository_error() throws VcsException { String unrelatedRepositoryStderr = "abort: repository is unrelated\n"; @@ -64,11 +84,6 @@ commandResult.checkCommandFailed(); } - public void should_detect_failure_with_non_zero_exit_code() throws VcsException { - CommandResult commandResult = commandResultFor(execResult().withExitCode(1)); - commandResult.checkCommandFailed(); - } - ExecResultBuilder execResult() { return new ExecResultBuilder();