Search code examples
mavenjenkinsmaven-surefire-pluginmaven-deploy-plugin

Keeping the maven deploy plugin from deploying on test failures


I'm a long time user of the maven-release-plugin which will not release (aka deploy jars to maven repo) if there are unit test failures.

For various reasons I want to use only the maven deploy plugin but apparently will still deploy even if there are test failures in the maven-surefire-plugin.

Consequently instead of just

mvn clean deploy

I must setup my CI to do a two step analagous to (shell):

mvn clean test && mvn deploy -DskipTests=true

I have made sure surefire is not set to ignore failures. Ideally I would not like to run two separate processes.

Certainly deployment on test failures can't be the default? Am I missing something?

EDIT it appears to be a Jenkins issue.. Can't reproduce

I'm not sure why or how Jenkins forces the maven build to continue on test failure (I assume this is for reporting) but it doesn't show any of the options being passed to for it to continue. It appears to only happen when Jenkins says "Modules changed, recalculating dependency graph".


Solution

  • You are encountering a known issue (or feature, depending on tastes) of Jenkins, which in Maven builds (hence created from the Maven Jenkins job template) would always pass by default -Dmaven.test.failure.ignore=true to the concerned Maven build, mainly because it would set the status of the build to UNSTABLE and not FAILED in case of test failures.

    This behavior has already been tacked in different Stack Overflow threads, here and here for some references, and it is also an open ticket (providing detailed description) on the Jenkins JIRA platform, although since already a while and would probably not be fixed (or at least clarified in the job configuration UI).

    However, the behavior is not provided when creating a Maven build from a freestyle Jenkins job template, that is, using a template which is not already pre-configured for Maven and hence no maven.test.failure property would be passed by default.

    The guideline indeed is to not deploy artifacts in case of test failures (which is the default behavior of the maven-surefire-plugin btw), which you can tackle in different ways:

    • Using a freestyle Jenkins job template and hence taking full control over the Maven build execution, although giving up on some nice pre-configuration
    • Keep the Maven Jenkins job and explicitly pass the -Dmaven.test.failure.ignore=false option as part of the initial mvn clean deploy command
    • Split the job in several build steps and only execute the next one if the previous was strictly successful (and not successful/unstable). A first step would be the classic mvn clean install, leaving then a next step to deploy either via Maven (see next) or a Jenkins plugin (there are Artifactory/Nexus Jenkins plugin which handle this task nicely, with the direct advantage of easier credentials and repositories management for snapshot/releases and hence more governance/security on CI side, removing noise from the pom.xml file or from every developer's maven settings).

    Concerning the additional Maven step which would only deploy, some considerations to also address some points in the comments above:

    There is a relevant difference between mvn deploy and mvn deploy:deploy, where the former is invoking a Maven phase and hence in cascade each phase from validate till deploy (hence, compile, test, package, e.g.) and each and every potential plugin execution configured in the pom file for a certain phase; the latter instead is only invoking a goal, the deploy goal of the maven-deploy-plugin, with the obvious direct advantage of performances (it's only performing one quick action and not the whole build again) and concerns (it's only performing what we actually really want at this stage).

    Yes, you can skip tests and the maven-jar-plugin would not re-package the application once again, e.g., and further default optimization provided by Maven, but still the former would be much slower and less correct.
    However, deploy:deploy would not work because of missing information in the Maven build context, looking simply at the target folder would not be enough to identify what to deploy, Maven needs to know which artifact is attached to the current build to be deployed. The additional jar:jar comes to the rescue in this case, not re-packaging anything but simply detecting what it was supposed to be packaged, attaching it as an artifact to the build context and making the maven-deploy-plugin happy. This mechanism is also explained in this Stack Overflow answer, as previously pointed out in the comments.