Avoiding circular dependencies between Maven plugin build and test - maven

I have a project with the following subprojects:
foo-codegen
...which, as the name implies, performs code generation...
foo-maven-plugin
...which invokes foo-codegen during the build process.
Generally speaking, this works fine. The problem, though, is when I want to test foo-codegen: foo-maven-plugin isn't yet available during foo-codegen's build cycle if we're putting things together in dependency order, but the build process for the tests invokes that plugin to actually perform the necessary code generation.
What's the right way to break this chain? Should I move foo-codegen's tests into a third subproject? Use the Maven Invoker plugin rather than foo-maven-plugin for doing code generation during the test phase? Something else?

If you do a mvn install or mvn deploy to a repository on the plugin first, then you can run them any order and do a mvn compile separately.

Related

what are the proper stages for Gitlab CI/CD for a maven deploy?

I am using Gitlab CI/CD for a Java/Maven project and am confused by the many examples which show multiple stages, where each stage calls a specific Maven phase (e.g. clean, compile, test, install)
The maven documentation is very clear that each phase implicitly invokes all prior phases. So my question is, why do the examples not just invoke the last phase listed in the stages? For example, if the last non manually-invoked stage in the yml does an 'mvn install', why not just have that be the sole stage in the yml? It seems it is just a waste of CPU and time since the install will also call 'clean, compile, test, which have already all been called as part of the previous stages in the pipeline.
The "tutorials" that advice you to first call mvn compile then mvn test etc. have not understood the Maven lifecycle.
Just call one command, like mvn install for installing or mvn deploy if you want to deploy it with the help of Maven to some Maven repository.
The main reason for running different maven goals in different stages is clarity.
If a test fails and the pipeline has one job which runs mvn deploy you need to take a look at the logs why the pipeline failed.
But if a separate job exists where mvn test is executed you see at a glance that the pipeline failed because of tests.
In the example from the gitlab documentation they use cache to cache the output of mvn compile so the maven goals in the next steps don't compile from scratch but use the cache instead.

How to write a Maven plugin IT test that correctly fails its build, resulting in an overall pass?

When generating a skeleton Maven plugin from archetype, the new project includes a Maven project under the src/it directory. It is an integration it (hinted at by the it dir name) and fresh out-of-the-box it passes when run during Maven's integration-test phase.
There are nearly 10 such IT Maven projects, a subset of which intentionally result in BUILD FAILURE, and attendant verify.groovy scripts that ensure those builds fail for the correct reason. Ideally each IT test sub-build that fails for the correct reason results in that IT test passing, but by including any of these failing IT tests as part of the whole integration test suite causes the overall Maven run to fail as well, which is incorrect in my case.
How do I coax Maven to run those failing Maven sub-builds, ignore their build results, but honor the results of their Groovy verification scripts?
Edit: One IT test (disabled) is committed here.
If you like to write an integration test which is intended to fail as a result
you have to express this via the invoker.properties file like this:
invoker.buildResult=failure
The full description of the file can be found in the documentation.

Generated code is not compiled

I wrote a Mojo that creates a new Java class and puts it in /target/generated-sources/annotations. in addition, I have configured build-helper-maven-plugin to declare that folder as source folder.
The problem is when I do: mvn clean install from CLI it generates the source file but it doesn't compile it.
Note, if I run Maven Install from within Eclipse (using the m2e connector) then it works fine.
What am I missing?
Without an actual plugin definition, we can only speculate.
I can't comment on m2e, I see one obvious difference that you state by yourself: mvn clean install vs mvn install, but from the "bare" maven's standpoint,
here is one possible reason:
Maven has a concept of phases that comprise the lifecycle. An information about phases of default lifecycle is available here
Plugins (more precisely the "goals" of plugins) are something that usually gets attached to a particular phase.
Maven compiler plugin is attached to the compile phase, for example.
So, maybe the plugin that you've developed runs later than the compiler plugin.
Usually, source generation plugins are attached to generate-resources phase.
Its possible to run a full lifecycle in maven, in fact its what people usually do, for example, running mvn test actually means, run all phases of the default lifecycle up-to (including) phase test.
It's also possible however to run a particular plugin goal "directly" without attaching it to the phase. Of course, in this case, its pre-conditions should be met.
For example, mvn surefire:test means that we should invoke the surefire plugin directly. Of course the source code and test code should be compiled beforehand (bytecode has to exist in the target directory)
So I suggest you to run the following series of commands (Adjust if you have tests):
Run mvn clean install on the plugin project to place it to local m2 repo
Run the plugin directly: mvn ::: and check
whether the source is generated in the target folder
Make sure in pom.xml of the project that the source folder are configured correctly
Run mvn compile (phase up-to, including, compile) on pom even without the plugin
After this phase, there will be compiled sources in the target directory. Don't run
clean because it will wipe out all the target directory
This will effectively help to make sure that plugin does the job right

Maven plugin execution change Maven properties or skip build lifecycle steps

When I build my application with maven, I run mvn clean install. As a part of the install lifecycle, I run appengine:devserver_start from Google's GAE Maven plugin. This appears to be already bound to a step in the lifecycle and therefore it reruns some build steps from the beginning, even though me running mvn install did those. For example, the resources step is rerun. I had my own Java script run to download the latest resources for my build. But because of appengine:devserver_stop, I need to uselessly run this cript again because the resources step is re-executed.
I can think of two ways I can avoid this, but I'm not sure how to configure both ways. The first would be to somehow skip re-running build steps that I've already run. The other way would be to change the Maven POM properties just for the plugin execution. I have a Maven property set, either to true or false, that I can use to set the skip setting for the Java script I use during resources (because I run this script using the exec-maven-plugin). Think of this as a Maven property that can be set with the -D flag. Can I have this property changed just for the plugin?
If you are having trouble thinking about my scenario, consider what happens when you run mvn compile install. All build lifecycle steps until compile will run, then all compile steps until install will run, including compile.
A common/easy way to solve this kind of problems is to use maven profile. Just create a new profile that includes the plugin with preferred phases.
You should probably don't fight with it and just run clean appengine:devserver_start instead of clean install. Read my answer here for a more detailed explanation:
https://stackoverflow.com/a/17638442/2464295

mvn test on multi module project?

I have a strange issue and I don't know if my conclusion is correct. I have a multi module project with two children:
Rector build order:
mvn-project-test
mvn-project-core
core depends on test (so the build order is correct). Of course, running 'mvn test' doesn't install any artifacts locally. When running it, maven complaints (correctly) that ~/.m2/respositories/...../mvn-project-test-1.0-SNAPSHOT.jar is missing and the core build fails.
Shouldn't maven use the dependencies from the target folder of other multimodule children? Or must I always use 'mvn test install' on multi module projects? (Or third, I'm completely wrong and my whole project configurationis somehow broken)
Finally, the test project hasn't any content, yet, just dependencies so the jar is empty. But that shouldn't be a problem, right?
Cheers,
Jan
There were ideas for Maven 3 to allow the various mojos to see the whole build and do magic like "if none of my upstream projects changed, skip my tests" and things like that.
But as it is, each module is independent. Dependencies will only be resolved from the local repository. So if you don't mvn install, your tests won't work.

Resources