I've got a (mostly) working plugin developed, but since its function is directly related to the project it processes, how do you develop unit and integration tests for the plugin. The best idea I've had is to create an integration test project for the plugin that uses the plugin during its lifecycle and has tests that report on the plugins success or failure in processing the data.
Anyone with better ideas?
You need to use the maven-plugin-testing-harness,
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-plugin-testing-harness</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
You derive your unit test classes from AbstractMojoTestCase.
You need to create a bare bones POM, usually in the src/test/resources folder.
<project>
<build>
<plugins>
<plugin>
<groupId>com.mydomain,mytools</groupId>
<artifactId>mytool-maven-plugin</artifactId>
<configuration>
<!-- Insert configuration settings here -->
</configuration>
<executions>
<execution>
<goals>
<goal>mygoal</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Use the AbstractMojoTest.lookupMojo(String,File) (or one of the other variations) to load the Mojo for a specific goal and execute it.
final File testPom = new File(PlexusTestCase.getBasedir(), "/target/test-classes/mytools-plugin-config.xml");
Mojo mojo = this.lookupMojo("mygoal", testPom);
// Insert assertions to validate that your plugin was initialised correctly
mojo.execute();
// Insert assertions to validate that your plugin behaved as expected
I created my a plugin of my own that you can refer to for clarification http://ldap-plugin.btmatthews.com,
If you'd like to see some real-world examples, the Terracotta Maven plugin (tc-maven-plugin) has some tests with it that you can peruse in the open source forge.
The plugin is at: http://forge.terracotta.org/releases/projects/tc-maven-plugin/
And the source is in svn at: http://svn.terracotta.org/svn/forge/projects/tc-maven-plugin/trunk/
And in that source you can find some actual Maven plugin tests at: src/test/java/org/terracotta/maven/plugins/tc/
Related
Background:
I am working on a open source tool called draw.io which is based on ANT build system and uses Java servelets to handle request. I am supposed to migrate it to spring boot with using same front end files. I put those files in static folder and tried to build the project. I figured that the front end js files were not getting build (i.e. were not getting converted to app.min.js, which is the main entry point for front end files), in the process and none of the js changes were getting reflected in the file.
I figured that this process was mentioned in build.xml as part of various steps which is ANT specific configuration. Now, I have to achieve the same in maven as the migration process.
How do we convert build.xml to maven or what is the maven alternative of achieving the tasks mentioned in the build.xml as part of build process?
This is the high level view of build.xml:->
I am also providing the link of build.xml here...
Please provide me with some direction.
Before migrating to maven, I hope you understand why you are moving to maven from ant.
You should try for finding alternative plugins for the relevant ant task. The below plugin might do what you are trying to achieve in ant
<plugin>
<groupId>com.github.blutorange</groupId>
<artifactId>closure-compiler-maven-plugin</artifactId>
<version>2.16.0</version>
<configuration>
<!-- Base configuration for all executions (bundles) -->
<baseSourceDir>${project.basedir}/src/main/resources</baseSourceDir>
<baseTargetDir>${project.build.directory}/generated-resources</baseTargetDir>
</configuration>
<executions>
<!-- Process all files in the "includes" directory individually-->
<execution>
<id>default-minify</id>
<configuration>
<encoding>UTF-8</encoding>
<sourceDir>includes</sourceDir>
<targetDir>includes</targetDir>
<includes>**/*.js</includes>
<skipMerge>true</skipMerge>
<closureLanguageOut>ECMASCRIPT5</closureLanguageOut>
</configuration>
<goals>
<goal>minify</goal>
</goals>
<phase>generate-resources</phase>
</execution>
</executions>
</plugin>
More details about the plugin : closure-compiler-maven-plugin
There are few cases during my ant to maven migration, I came across some custom tasks which I was not able to find appropriate plugins.
I used maven-antrun-plugin which keeps existing ant tasks in maven.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
...
</executions>
</plugin>
More details about how to use the maven antrun plugin : See this
tutorial
For Maven, you need a pom.xml. There you need to define and configure the plugins you need. If you have a specific procedure written in Ant that you want to reuse, you can call it with the Maven Antrun Plugin.
Generally, Maven is very different from Ant. You don't write procedural code, but configure plugins running in a lifecycle.
I have a Spring Boot multi module Maven project, I can run integration tests with:
mvn clean verify
and it works well. I now want to run the same integration tests from a container and I don't want to embed all the source code in the container.
My question is : how can I run the Maven Failsafe Plugin without using the source code?
I tried to run the failsafe:integration-test goal and setting the dependenciesToScan parameter, from the command line:
mvn failsafe:integration-test -DdependenciesToScan=com.myorg:proj-tests.jar
but no tests are found.
P.S.1: I've seen this similar question Running spring tests from executable jar. But I don't need to run the tests without Maven. I prefer to run tests from the command line with Maven than adding code or modifying the structure of my project.
P.S.2: I'm using maven-failsafe-plugin 2.22.2 which is the version provided with Spring Boot 2.1.8.
From the docs:
Since version 2.22.0 you can scan for test classes from a project
dependency of your multi-module project.
It means the tests (proj-tests.jar) must be a dependency of the project. As you cannot have a dependency to the tests jar in the same project where you build them, the solution is to have another module or pom file. Example:
<groupId>failsafe.use.jar</groupId>
<artifactId>failsafe-use-jar</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
...
<dependency>
<groupId>com.myorg</groupId>
<artifactId>proj-tests</artifactId>
<version>0.0.1-SNAPSHOT</version>
<classifier>tests</classifier>
</dependency>
...
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version>
</plugin>
</plugins>
</build>
The proj-tests is a project dependency and can be created with:
<groupId>com.myorg</groupId>
<artifactId>proj-tests</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.2</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
See Guide to using attached tests
To run the integration tests from the container you obviously need all the dependencies installed in the local
(container) maven repository or deployed in remote. Then you can run with:
mvn failsafe:integration-test -DdependenciesToScan=com.myorg:proj-tests
Note that the format of the dependenciesToScan property is groupId:artifactId (you run with the name of jar instead of artifactid)
As another note, for integration tests failsafe searches by default for class files ending in IT (integration test).
I have a number of Maven projects being built my Jenkins server. These projects have dependencies on each other, e.g.
service-base -> java-base -> pom-base
In other words, the Maven project service-base depends on the Maven project java-base. Naturally, my POM files look like this:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>my.com</groupId>
<artifactId>service-base</artifactId>
<dependencies>
<dependency>
<groupId>my.com</groupId>
<artifactId>java-base</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>
The issue is that none of my Maven projects have "releases" per-se, since I'm using continuous integration to release my changes. Currently, I allow artifact overwriting in my Maven repo and keep all of my versions at 1.0.0. This is because I release my packages many times a day and changing the versions in all the POM files each time I submit a new package version.
Ideally, what I would like is for Jenkins to generate a new version, e.g. 1.0.{BUILD_NUMBER} and then for it update the dependencies all the way up the dependency tree.
Question: Is this possible? Or does anyone have any other solutions to versioning?
Here is how I achieved the same, using Maven profiles, Maven classifiers and Jenkins parametrized builds.
You can define a jenkins profile (or whatever name you prefer) in the pom of the concerned projects. This profile will not be active by default, so your local builds will keep on working as usual. However, this profile will be activated on the Jenkins builds (via the -Pjenkins option on the Maven execution).
How this profile look like in the project at the top of the hierarchy:
<profiles>
<profile>
<id>jenkins</id>
<properties>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<packaging>${project.packaging}</packaging>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<id>generate-default-version</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>${BUILD_NUMBER}</classifier>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>install-default-version</id>
<phase>install</phase>
<goals>
<goal>install-file</goal>
</goals>
<configuration>
<file>${project.build.directory}/${project.build.finalName}-${BUILD_NUMBER}.${project.packaging}</file>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
What is the profile doing?
We are using the Maven Jar Plugin to generate on the package phase yet another artefact for the same project, so the project will create the normal jar plus another jar having as classifier the BUILD_NUMBER (i.e. myproject-1.0.jar and myproject-1.0-4567.jar)
We are also using the Maven Install Plugin to install the additional artefact (the myproject-1.0-4567.jar) into the local Maven cache (so it will be visible to other dependent projects)
We need to define some properties for the Install Plugin, otherwise the install-file will not work
Hence, when on your Jenkins build you will execute the following:
mvn clean install -Pjenkins -DBUILD_NUMBER=${BUILD_NUMBER}
Jenkins will actually pass its BUILD_NUMBER to Maven, which will use it as defined in the jenkins profile and create (and install) an additional artefact for us using it as classifier.
Fine, now we have a dynamically created artefact using the Jenkins build number and available for other projects/builds.
But how other projects can use it?
We define in the dependent projects another profile (or again called jenkins for coherency) and re-define the dependency we now need at runtime:
<profiles>
<profile>
<id>jenkins</id>
<dependencies>
<dependency>
<groupId>com.sample</groupId>
<artifactId>test</artifactId>
<version>1.1.0</version>
<classifier>${BUILD_NUMBER}</classifier>
</dependency>
</dependencies>
</profile>
</profiles>
Note: we are actually overriding as part of the profile a dependency and saying we want that specific classifier for it. Which classifier? The BUILD_NUMBER classifier, which will be available in the local Maven cache of the Jenkins server because installed by the previous build.
But how can the dependent build know which build number and as such which classifier to use, dynamically?
Using Jenkins parametrized builds and the Jenkins Parametrized Trigger plugin.
So, to summarize:
Provider project defines the profile to create additional classifier
Consumer project defines the profile to use as dependency a specific classifier
If a project is Provider for others and Consumer of others, it can then merge the two approaches above in the same profile
The first Jenkins build activates this specific profile and pass to Maven its build number
The downstream Jenkins builds are triggered by the first, which is passing them its build number via the Parametrized Plugin
Each downstream build would then resolve the classifier specified by the parameter and, if required, also create yet another classifier for its own build (according to its profile)
Using this approach, you local builds will keep on working as usual and no classifier would be used, while Jenkins builds would use an additional classifier used across them.
Currently we are working on the big maven project that has about 100 modules, some of them have submodules as well.
Some of modules use Maven Build Number plugin. The project is hosted under subversion.
Recently we started to use git locally in our development team.
After cloning subversion repo and trying to build the Project, we received following well known error:
The svn command failed.
Command output:
svn: ‘.’ is not a working copy
Unfortunately in our case it is not an option to create a new profile or just remove plugin definition from POM (this will follow to messing up hundreds of POM files).
I found the following article http://abstractionextraction.wordpress.com/2012/09/27/git-svn-vs-maven-build-number-plugin/ but honestly, it's not something that I would really like to do...
Is there any smart way to disable this plugin. Like command-line parameter?
I think you may skip failure on obtain revision without change project pom.xml - buildnumber-maven-plugin has option revisionOnScmFailure which you may use like:
mvn -Dmaven.buildNumber.revisionOnScmFailure=no-scm package
In that case value no-scm will be used if scm call was unsuccessful. Off course you may change it and provide any other string.
Per the mojo documentation, you could use the revisionOnScmFailure property.
However, it doesn't have a command line option. You'll have to modify those pom.xml files.
See "Defining Parameters Within a Mojo" in the Maven Java Plugin Development Guide
One approach would be to use a property in your pom to specify the execution phase of the build number plugin, as shown below.
<project>
..
<properties>
<buildnumber.plugin.phase>validate</buildnumber.plugin.phase>
..
</properties>
..
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>1.2</version>
<executions>
<execution>
<phase>${buildnumber.plugin.phase}</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
<configuration>
..
</configuration>
</plugin>
</plugins>
..
</project>
Then provide the property on the command line to disable the plugin, as shown in the following example.
mvn install -Dbuildnumber.plugin.phase=none
Something bother me a lot...
On a big project with many dependencies, some of them are set as SNAPSHOT in Maven2.
The matter is that it seems i can't get the sources through Eclipse without loading the project or fixing the dependency to the last release.
For debugging, it's really annoying me...
EDIT
This is what i get in eclipse maven console:
26/08/10 11:31:46 CEST: Downloading http://repo-maven/archiva/repository/snapshots/com/blabla/1.1-SNAPSHOT/blabla-1.1-20100824.213711-80-javadoc.jar
26/08/10 11:31:47 CEST: Could not download sources for com.blabla:blabla:1.1-20100824.213711-80
On archiva i can see the deployed stuff i want to retrieve in eclipse...
Repository snapshots
Group ID com.blabla
Artifact ID blabla
Version 1.1-20100824.213711-80
Packaging jar
Parent com.blabla bla 1.1-SNAPSHOT (View)
Other Versions 1.1-20100824.213535-79
I can download sources of this artifact with my browser but not within Eclipse... Any idea?
The matter is that it seems I can't get the sources through Eclipse without loading the project or fixing the dependency to the last release. For debugging, it's really annoying me...
Well, these modules are probably not publishing source JARs as part of the "regular" build process (i.e. outside the release). If these modules are under your control (which is my understanding), configuring the Maven Source Plugin to produce source JARs for them and deploying them in your corporate repo should solve the problem. From the Usage page:
Installing the sources along with your artifact
There are two ways to do this. You can
either bind this plugin to a phase or
you can add it to a profile. The goals
source:jar-no-fork and
source:test-jar-no-fork are preferred
for binding the goal to the build
lifecycle.
Installing the sources using a phase binding
Here is how you would configure the
plugin in your pom.xml to run
automatically during the verify phase:
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.2</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
</project>
We are using the verify phase here
because it is the phase that comes
before the install phase, thus making
sure that the sources jar has been
created before the install takes
place.
Installing the sources using a profile
If you want to install a jar of your
sources along with your artifact
during the release process, you can
add this to your pom.xml file:
<project>
...
<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.2</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
...
</project>
Using a profile would probably be a good idea so that building source JARs will only be done by the build running at the CI server level but not on developer machines.