Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maven multi-module deploy to repository only after successful unit tests

Question: What is the best solution for executing a 'mvn deploy' such that the deploy part is only run after all unit tests succeed and no processing steps are duplicated?

I was hoping the simple answer was: Execute maven command 'x' (or use a flag) such that the deploy can be run without invoking the prior goals in the default lifecycle.

Sadly this does not appear to have a simple answer. I have included the details on the path I have followed so far below.

We have the following three requirements:

  • Execute the maven deploy goal to deploy all multi-module artifacts to a remote repository.
  • Only deploy if ALL unit tests across all projects pass.
  • Do not repeat any processing.

We started with simply "mvn clean deploy", however we noticed a couple issues:

  • the build would stop before completing all unit tests :: so we added the --fail-at-end flag
  • The deploy goal would execute against any modules that were successful.

This results in a "corrupted" state where the remote repository may only has a partial deployment (if there were modules with failures later in the build).

We looked at 3 different solutions:

  1. Staging the artifacts prior to deploying :: this was determined to be too heavy for a fully automated process.
  2. Use a profile to override the default lifecycle such that 'mvn deploy -Pci-deploy' would run without invoking any prior goals :: this worked and was fast, but is obviously an unconventional approach.
  3. Simply running 'mvn clean package' and then only iff successful execute 'mvn deploy' :: this appears to work and seems to only take a minor hit when the goals are invoked (though some of them are smart enough not to reprocess an unchanged workspace)

I pose this question to the community with the background details I have provided to determine if there is a better approach or a strong opinion regarding (potentially) making one of the following requests:

  • A new deploy goal that can run separate and apart from all other lifecycle goals with the expectation that: all prior steps have already been run and that it will execute the deploy identically to "mvn deploy"
  • a flag in the deploy goal which would effectively disable the previous goals.

a little more out of the box and definitely against the current convention:

  • a flag that would tell maven to run the [unit] test goal for all modules prior to proceeding.

Notes:

  • We are using Jenkins, but for the purposes of this question the CI environment is not the complication.
  • I tried the 'mvn deploy:deploy' goal, but it had a number of unclear errors.
  • I have not considered integration tests as part of the requirements.

Update 8/20/2013

I tested the deferred deploy plugin and determined that the tool worked as expected, but took way to long.

For our code base:

  • mvn clean deploy: for all goals executed in 2:44
  • mvn clean install 'deferred-deploy-plugin': for all goals executed in 15 min
  • mvn clean package; mvn deploy -Pci-deploy a custom build profile that disables the earlier goals executed:
    • for all goals (including deploy): 4:30
    • deploy only: 1:45
  • mvn clean package; mvn deploy -Dmaven.test.skip=true on the same workspace executed:
    • for all goals (including deploy): 4:40
    • deploy only: 1:54

The clean package followed by deploy skipping the tests runs faster than the deferred deploy and accomplished our desire to delay the deploy until after the tests succeed.

There appears to be a minor time hit for when the deploy lifecycle executes and exits each of the preceding goals (process, compile, test, package, etc). However the only alternative is to hack a non-standard execution, which only saves 10 seconds.

like image 243
Jared Avatar asked Aug 12 '13 17:08

Jared


1 Answers

There's a new answer now. Since version 2.8 of the maven deploy plugin there's a way to do this "natively". See the jira issue for details.

Basically you need to force at least v2.8 of the plugin

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-deploy-plugin</artifactId>
   <version>2.8</version>
</plugin>

and use the new parameter deployAtEnd. more info here. This setting usually goes along with installAtEnd of the maven-install-plugin

like image 190
Hilikus Avatar answered Oct 27 '22 22:10

Hilikus