I'm working on creating GitLab CI/CD pipeline components to provide the following processes:
- build an Java jar file (mvn compile)
- run tests (mvn test)
- deploy jar file to a registry (mvn deploy)
I want these to be separate jobs, so that a build failure is separate from a test failure. Also, there may be situations where there are no tests, so that job could be optional.
Based on my experience with Maven, even if I run mvn test
by itself, it is still essentially running a compile before invoking any tests. I was hoping there was the capability to "save" the build artifacts from the build stage and make them available to the test stage, without having Maven basically recompiling everything. Similarly, I think it's also recompiling the code at the deploy stage (not 100% sure of that, though).
Does anyone know if this is possible with Maven?
My Rationale
GitLab CI/CD pipelines are arranged as a set of stages that run in order. There can be multiple jobs within a stage, or only one as the pipeline needs dictate. My idea is that I would have build, test, package and deploy stages where the following would happen.
build - run mvn clean compile
. The job (and pipeline) fails if the job script (running Maven) fails. This would give developers the opportunity to fix the problems and re-commit.
test - run mvn test
. Run tests and fail the job and pipeline if there are any test failures. Developers can address any issues and commit changes again. It would save time if it didn't compile the source code a second time and instead could be preserved from the build stage and used in this stage.
We also wanted to be able to "soft fail" the test stage if no tests were found (-DfailIfNoTests
). The pipeline would not fail, however the pipeline highlights the test stage with a warning to alert developers that no tests were found and that they should consider creating some.
package - run mvn package
. Package the compiled code into a Jar file, suitable for "deployment" to a GitLab package registry.
deploy - run mvn deploy
. Push (via mvn deploy
) the Jar file to a GitLab package registry. This is not a Maven repository.
Perhaps it makes more sense to combine the package
and deploy
stages together as one. Again, it would save time if either of these stages did not need to compile the code, but could utilize the artifacts created from the build stage.
I'm working on creating GitLab CI/CD pipeline components to provide the following processes:
- build an Java jar file (mvn compile)
- run tests (mvn test)
- deploy jar file to a registry (mvn deploy)
I want these to be separate jobs, so that a build failure is separate from a test failure. Also, there may be situations where there are no tests, so that job could be optional.
Based on my experience with Maven, even if I run mvn test
by itself, it is still essentially running a compile before invoking any tests. I was hoping there was the capability to "save" the build artifacts from the build stage and make them available to the test stage, without having Maven basically recompiling everything. Similarly, I think it's also recompiling the code at the deploy stage (not 100% sure of that, though).
Does anyone know if this is possible with Maven?
My Rationale
GitLab CI/CD pipelines are arranged as a set of stages that run in order. There can be multiple jobs within a stage, or only one as the pipeline needs dictate. My idea is that I would have build, test, package and deploy stages where the following would happen.
build - run mvn clean compile
. The job (and pipeline) fails if the job script (running Maven) fails. This would give developers the opportunity to fix the problems and re-commit.
test - run mvn test
. Run tests and fail the job and pipeline if there are any test failures. Developers can address any issues and commit changes again. It would save time if it didn't compile the source code a second time and instead could be preserved from the build stage and used in this stage.
We also wanted to be able to "soft fail" the test stage if no tests were found (-DfailIfNoTests
). The pipeline would not fail, however the pipeline highlights the test stage with a warning to alert developers that no tests were found and that they should consider creating some.
package - run mvn package
. Package the compiled code into a Jar file, suitable for "deployment" to a GitLab package registry.
deploy - run mvn deploy
. Push (via mvn deploy
) the Jar file to a GitLab package registry. This is not a Maven repository.
Perhaps it makes more sense to combine the package
and deploy
stages together as one. Again, it would save time if either of these stages did not need to compile the code, but could utilize the artifacts created from the build stage.
1 Answer
Reset to default 2To simplify the things (@khmarbaise gave you the right direction) - it's probably (and likely) not what you would want to do, unless your delivery relies on direct deployment of artifacts to the runtime environments skipping the binary management system.
First, mvn test
will indeed compile the code, but it will not produce the jar files. mvn package
will do - but it will not run the integration tests (if any) which would be run by mvn verify
.
Then, if there's no tests, there is no need to avoid the tests
or verify
phases - they will not fail, they will just report that no test classes were found.
So, at this point we're ending up with mvn verify
as the minimum, and then thinking about optimizations:
I was hoping there was the capability to "save" the build artifacts from the build stage and make them available to the test stage, without having Maven basically recompiling everything.
Too early - because you typically need to make sure that your application could be successfully built from scratch. Moreover, it's not necessarily true that your application will be built on a same build runner that already has all the dependencies downloaded. So it makes perfect sense to recompile everything in a CI environment, adding clean
phase to clean up the target
directories, resulting in mvn clean verify
. Also, for advanced scenarios, three is an option to experiment with incremental builds, but they are typically supported by the external systems (TeamCity, IntelliJ IDEA etc.) or Maven extensions, as it goes a bit against the Maven lifecycle design.
Only after this you can make a decision on how to proceed with the build artifacts.
Further steps depend on your deployment process. But in a CI/CD environment it usually doesn't make much sense to store the artifacts in the Maven local repository (which is being done by mvn install
that would be implicitly invoked by mvn deploy
, so instead of using deploy
you might want to consider uploading the artifacts by an external tool or another Maven plugin.
Also (and probably this is what you wanted to hear in the first place), you can try to make use of separate plugin goals instead of phases that aggregate them - for example, mvn deploy:deploy
.
compile
will not create a jar file or any kind of packaging... that will be done later in the life cycle. The life cycle phasetest
is intended to run the unit tests... and usingdeploy
life cycle will include previous cyclepackage
will will produce the resulting jar files... If you just usetest
life cycle phase this will include previous life cycle phases includingcompile
(check maven.apache./guides/introduction/…) – khmarbaise Commented Jan 31 at 20:28mvn deploy
and everything will run as required in the order needed (see docs)... If tests fail the build will not continue to the next phases... if everything is recompiling everything there is something wrong... – khmarbaise Commented Jan 31 at 20:29