Maven multi-module deploy to repository only after

2020-05-23 07:03发布

问题:

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.

回答1:

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



回答2:

As an alternative, I also found this http://code.google.com/p/maven-deferred-deploy-plugin/

A maven plugin that iterates through all projects in a reactor and executes a deploy on each project individually. Can be used to produce a near-atomic build for a reactor by deferring artifact deployment until the install phase has completed.

Sounds alot like what you were asking for. I still think my other answer is easier to implement since you use jenkins, just check a checkbox



回答3:

Two things.

  1. Disabling all the previous phases i don't see it as an option. It is a basic feature of maven, you would be altering the standard lifecycle so i highly doubt anyone would implement something in a plugin to allow this
  2. Since you said you use Jenkins, there is a setting in jenkins specifically for the case of deploying at the end to guarantee that the repo is not in a corrupt/intermediate state

In "Post-build actions"

Deploy artifacts to a Maven repository. In comparison with the standard mvn deploy, this feature allows you to deploy artifacts after the entire build is confirmed to be successful. This prevents a typical problem in Maven, where some modules are deployed before a critical failure is discovered later down the road, rendering the repository state inconsistent. Note that regardless of this configuration, you can always manually come back to Jenkins and deploy any of the past artifacts to any repository of your choice, after the fact. To use this feature you shouldn't deactivate the automatic artifact archiving.

I have never used this so i can't confirm whether it works, I just know it's there for this particular use-case