Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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".

like image 990
Adam Gent Avatar asked Jul 20 '16 16:07

Adam Gent


People also ask

What does mvn clean deploy do?

clean : removes files generated at build-time in a project's directory ( target by default) install : installs the package into the local repository, for use as a dependency in other projects locally.

What is the purpose of the deploy plugin for Apache Maven?

The deploy plugin is primarily used during the deploy phase, to add your artifact(s) to a remote repository for sharing with other developers and projects. This is usually done in an integration or release environment.

Does mvn deploy run tests?

When you call mvn deploy , mvn will also execute every lifecycle phase before deploy , in order: validate , compile , test , package , verify , install . Same for verify : validate , compile , test , package .

What is the different between mvn install mvn deploy?

mvn install: Deploys the packaged JAR/ WAR file to the local repository. mvn deploy: Copies the packaged JAR/ WAR file to the remote repository after compiling, running tests and building the project.


1 Answers

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.

like image 120
A_Di-Matteo Avatar answered Oct 19 '22 07:10

A_Di-Matteo