Trigger a Mojo programmatically from another Mojo - maven

Can I make a Mojo that runs during integration-test phase trigger another Mojo that runs during verify phase?
This question is a follow up on my previous question. I extended the frontend-maven-plugin with a parameter that delays build failure from integration tests until the verify phase to allow the post-integration-test phase to execute properly. This is often needed to clean up the environment (close DB, server, ...). Pull request commit available here.
The solution is rather hacky because it requires the user to add a verify execution phase, even if it doesn't do anything. Instead, I would like an execution on the integration-test phase to automatically execute a Mojo during the verify phase (without the user explicitly adding this to the Maven configuration). So the following:
<execution>
<id>npm run integration tests</id>
<goals>
<goal>npm</goal>
</goals>
<phase>integration-test</phase>
<configuration>
<arguments>run e2e</arguments>
<integrationTestFailureAfterPostIntegration>true</integrationTestFailureAfterPostIntegration>
</configuration>
</execution>
should trigger e2e tests to run during integration-test phase, but also needs to execute another Mojo during verify phase.
Is this possible and how would you do it?
UPDATE: I managed to add another pluginExecution at runtime to the plugin like so:
for (Plugin plugin : project.getBuildPlugins()) {
if("com.github.eirslett".equals(plugin.getGroupId()) && "frontend-maven-plugin".equals(plugin.getArtifactId())){
PluginExecution verifyExecution = new PluginExecution();
verifyExecution.addGoal("verify");
verifyExecution.setId("verify integration tests");
verifyExecution.setPhase("verify");
plugin.addExecution(verifyExecution);
}
}
but this does not seem to affect the runtime executions. The goal is a custom verify Mojo that performs the validation during the verify phase

Related

What does "echo" mean when it comes to using Maven?

I'm currently learning how to use Maven and have encountered a term called "echo". I was just wondering what it actually means?
There are few important concepts related to Maven Lifecycles, which
are worth to mention:
1) When a phase is called via Maven command, for example mvn compile,
only phases up to and including that phase will execute.
2) Different maven goals will be bound to different phases of Maven
lifecycle depending upon the type of packaging (JAR / WAR / EAR).
In the following example, we will attach maven-antrun-plugin:run goal
to few of the phases of Build lifecycle. This will allow us to echo
text messages displaying the phases of the lifecycle.
echo is an ant task which allow to print messages to console (system.out)
This makes sense when using maven-antrun-plugin which allow to execute ant tasks in a maven build.
It can be used to print some maven properties during the build as there is no built-in way to output value to console in maven.
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>${maven.antrun.plugin.version}</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<echo>Configuration properties :</echo>
<echo>service.endpoint=${service.endpoint}</echo>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
It means to use echo tag in ant script executed by maven-antrun-plugin:run. Nothing directly related to maven itself.

What is the recommended way to execute code at the end of the test phase in Maven?

I have some JUnit tests that execute in parallel in the test phase and output one .json file per test, and I want to call a custom Java method to do some aggregation and post-processing on those files after all of the tests have finished executing.
The integration-test phase is followed by the post-integration-test phase in the default Maven lifecycle, but the test phase is not followed by a post-test phase, and I would prefer not to abuse some other phase for this purpose.
Question: What is the recommended way to post-process the results at the end of the test phase?
As well described in another SO post, there is no post-test phase in Maven for good reasons (mainly, unit test is unit test).
However, in your case you don't need to create an additional Maven plugin, which would probably solve the issue but also add an additional layer of complexity in terms of maintenance, testing, sharing.
Since you already have the required code in a Java method - as mentioned in the question - it would probably make more sense to use the Exec Maven Plugin and its java goal.
You could hence simply add to your POM:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1.1</version>
<executions>
<execution>
<phase>test</phase> <!-- executed as post-test, that is, after Surefire default execution -->
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>com.sample.JsonFileAggregator</mainClass> <!-- your existing Java code, wrapped in a main -->
<arguments>
<argument>${project.build.directory}</argument> <!-- directory from where to load json files -->
</arguments>
<classpathScope>test</classpathScope> <!-- if your Java code is in test scope -->
</configuration>
</execution>
</executions>
</plugin>
That is, binding its execution to the test phase, Maven will executed it after any default binding (hence after the default Maven Surefire execution) and as such executed as a post-test.
Your existing Java code can then be invoked via a crafted (if not already existing) Java main, potentially passing to it arguments (like the directory from where to load the .json files, in the snippet above to the target folder, via its standard property ${project.build.directory}, as an example). Moreover, as mentioned in the snippet, your Java code may be located in test scope (that is, under src/test/java), hence to make it visible you would need to also configure the classpathScope accordingly.

How to run script in mvn as test

I would like to have the following scenario in Maven/Jenkins:
Run test scripts (bash/shell)
when the script exited with a problem (an error), then the Maven build on Jenkins should be on UNSTABLE and not FAILURE status
Question: How can I do it?
You can run scripts in Maven using the Exec Maven Plugin and its exec goal.
If you want to run the script during the test phase, then you can bind an execution of the plugin to it as following:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<id>run-test-script</id>
<phase>test</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<executable><!-- configure here your script .sh/.cmd --> </executable>
<arguments>
<argument><!-- configure here arguments, if any --></argument>
</arguments>
<workingDirectory><!-- configure here PWD, if required --></workingDirectory>
</configuration>
</plugin>
</plugins>
</build>
Note that you can also configure different successful exit codes via the successCodes configuration entry.
If the script fails, then the build will fail. However, you can change this behavior on the Jenkins build via the Jenkins Text Finder Plugin and configure it as Post-build Action:
You should set-up a regular expression which could be found as part of the Maven build output on Jenkins. As example, the regex .*Script Failed.* would match the string Script Failed printed by the script in such a case. So the build will actually fail, however we can change its status on Jenkins (but not on Maven)
You should check the option Unstable if found which will convert the status of the build from FAILED to UNSTABLE
As per documentation of the Unstable if found option:
Use this option to set build unstable instead of failing the build.
You can see an example of such a configuration in the image below:
As such, you would have a script executed in the test phase as you desired, the Maven build would fail if the script did so but the Jenkins build would change its status according to your configuration of the Text Finder plugin.
Also note: if you want Maven not to fail in case the script did, you can play with the successCodes as mentioned above and still make the Jenkins build change its status to UNSTABLE according to the same configuration of the Text Finder plugin. Hence different combinations are possible.

Why failsafe plugin requires both integration-test and verify goals?

I have the next pom.xml
<project>
...
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<argLine>${failsafeArgLine}</argLine>
<includes>
<include>**/dmg/*IT.java</include>
</includes>
<skipTests>${skipTests}</skipTests>
</configuration>
</execution>
</executions>
</plugin>
...
</project>
The problem is that when I'm taking off verify goal then the build is every time successful even if there was test failures.
And when I'm Taking off integration-test goal the integration tests simply do not run
Why failsafe plugin requires both integration-test and verify goals?
In Maven Failsafe plugin reference you can find simple answer why build is always successful
failsafe:integration-test runs the integration tests of an application.
failsafe:verify verifies that the integration tests of an application passed.
Without verify goal test results are not checked at all(but they are executed), so failsafe plugin requires integration-test goal to run tests, and verify to "verify" their results.
In Maven there are two types of test runner plug-ins, Surefire and Failsafe and they both serve different purposes. (I mention Surefire here because I feel it helps explain and contrast different types of failure in builds.)
Surefire
Surefire is a plug-in designed for your pre-deploy tests, such as Unit and Component tests. Surefire is guaranteed to return a failure (and therefore break your build) if any of the tests fail.
You want this behaviour in pre-deploy tests because you want to fail the build early if your tests fail, and as Unit and Component tests don't (or shouldn't) have any external dependencies it's safe to fail a build there and then.
Failsafe
Failsafe is a plug-in designed for post-deploy tests, such as Functional and Smoke tests.
Failsafe, as the name implies handles failures safely, by always returning a success exit code (as you have experienced in your build).
The reason behind this is for post-deploy tests you don't want test failures to immediately break the build because you may have spun up infrastructure, or seeded some test data into the system, which needs clean-up before the build is failed.
Therefore Failsafe splits the failure checking into the failsafe:verify goal which happens in the verify phase.
If you run Maven without parameters (assuming the normal jar lifecycle) you'll notice a phase between integration-test and verify called, post-integration-test. This is the phase which was designed for the tear down of any infrastructure or test data you may have injected into the system to run the tests.
... pre-integration-test, integration-test, post-integration-test, verify, ...
The phase before integration-test, pre-integration-test is designed for the said seeding and infrastructure creation.
To sum it all up, with pre-deploy tests you want to fail the build as early as possible, and so surefire guarantees this by exiting with a failure.
Whereas with post-deploy tests there are often external dependencies which need clean-up before you fail the build. For example in Kubernetes you may want to issue a rollback of the deploy and so failsafe:integration always returns a build success to guarantee you can perform the clean-up before failing the build by checking the status with failsafe:verify.
(The currently accepted answer just quotes the manual and doesn't explain why there are two commands and there are differences which is why I feel this answer is needed.)

Maven: Bind plugin execution to the execution of another plugin, not to a lifecycle phase

Note regarding the accepted answer: I accepted the answer because of strong circumstantial evidence. Nonetheless, this is circumstantial evidence, so take it with a grain of salt.
How can I have a plugin be triggered when the user runs a plugin goal, not a lifecycle phase? (This has been asked before, but the answer was to use a lifecycle phase.)
Case in point: I need release:branch to invoke regex-plugin to generate a branch with the current version as its name, minus the -SNAPSHOT suffix. This is what I have, which requires the developer to activate a profile and invoke the verify phase. I need the developer to simply invoke release:branch, which in turn should cause regex-plugin to run. In a bit of a marriage to Gitflow.
<profile>
<id>Release Branch</id>
<build>
<plugins>
<!-- On validate, compute the current version without -SNAPSHOT. -->
<!-- Put the result in a property. -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>regex-property</goal>
</goals>
<configuration>
<value>${project.version}</value>
<regex>^(.*)-SNAPSHOT$</regex>
<replacement>$1</replacement>
<name>project.unqualifiedVersion</name>
</configuration>
</execution>
</executions>
</plugin>
<!-- Also on validate, run the branch plugin, and use -->
<!-- the non-SNAPSHOT version thus computed in the branch name. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.3.2</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>branch</goal>
</goals>
<configuration>
<branchName>release/${project.unqualifiedVersion}</branchName>
<updateWorkingCopyVersions>true</updateWorkingCopyVersions>
<updateBranchVersions>false</updateBranchVersions>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
The intent is for release:branch to move the current snapshot version (say, 1.0.5-SNAPSHOT) into a new branch, which should be named after the version but without the superfluous -SNAPSHOT suffix (1.0.5). The current branch should then take on a new snapshot version (1.1.0-SNAPSHOT, not 1.0.6-SNAPSHOT, because we want release 1.0.x to have room for hotfixes, so we reserve it for the branch) (I don't have the automatic computation of the next snapshot version figured out yet, so, if you run the Maven configuration above with validate, you will have to enter it at a prompt).
The evidence presented so far is rather circumstantial. I've done some research of my own, so it's best I share it here. The below are either more of the same "it's not possible", or the building blocks for alternatives.
jetspeed:mvn plugin --- run a specified sequence of plugins; the configuration to run can be varied via a system property; IDE integration concerns
Executing goals before plugin runs (StackOverflow) --- same question answered in the context of a custom Mojo
Make Mojo run other goals (StackOverflow) --- again, from the context of a custom Mojo
Configuring default Mojo executions --- Maven page describing how Mojos run - more circumstantial evidence
Triggering phases before goal execution (StackOverflow) --- roundabout solution to my problem, unfortunately answered in the negative
INTERESTING: Guide to Ant plugin development --- appealing to me, because, while it requires writing a custom plugin, it's all Ant + Maven configuration, no code to compile; presumably a lower barrier to entry
Creating a parallel lifecycle --- appealing approach, because I could fully control the contents of the lifecycle to where it would use Gitflow verbs; unclear how IDEs would integrate this; learning curve and adoption barrier concerns exist
No, you can't bind to a plugin to another plugin. Only to a phase.
In Maven-internal terms, a "Mojo" is the thing that does work. A "plugin" is a collection of mojos wrapped up so you can reference them from the POM. Mojos bind to phases only.
From the plugin development documentation:
Each Mojo specified inside a plugin descriptor must provide the following
...
phase ... Defines a default phase to bind a mojo execution to if the user does not explicitly set a phase in the POM. Note: This annotation will not automagically make a mojo run when the plugin declaration is added to the POM. It merely enables the user to omit the <phase> element from the surrounding <execution> element.
For further confirmation, see the source of MojoExecution (the JavaDoc for this class isn't helpful) and notice that there are two possible sources of execution enumerated:
An execution that originates from the direct invocation of a goal from the CLI
and
An execution that originates from a goal bound to a lifecycle phase
No other way to kick off an execution means you're out of luck (barring extraordinary measures like rolling your own plugin that combines the effects of the two plugins you want to link and then using your custom plugin).

Resources