Passing parameters from Jenkins pipeline to maven plugin executed in shell - java

When trying to execute cucumber tests from Jenkins pipeline with the invocation looking like this:
sh '''mvn spring-boot:start \
exec:java \
-Dexec.classpathScope=test \
-Dexec.mainClass=io.cucumber.core.cli.Main \
-Dexec.args=\\"src/test-bdd/resources/features/set02 --glue gluepackage\\" \
spring-boot:stop
'''
after that line gets invoked, Jenkins will output the following:
20:39:31 + mvn spring-boot:start exec:java -Dexec.classpathScope=test -Dexec.mainClass=io.cucumber.core.cli.Main -Dexec.args="src/test-bdd/resources/features/set02 --glue gluepackage" spring-boot:stop
20:39:31 Unable to parse command line options: Unrecognized option: --glue
20:39:31
20:39:31 usage: mvn [options] [<goal(s)>] [<phase(s)>]
That basically means the shell is not passing the value of the -Dexec.args parameter to the exec plugin as a string but rather interprets that value as arguments to the mvn command. Obviously there's no --glue argument maven recognises, so the shell will print help on how to use maven and exit with a an error.
If I copy-paste the generated command into my terminal in the project directory and hit enter, it will run perfectly fine meaning the contents between quotes will be passed to the exec:java plugin command and the cucumber tests start and run as they should.
I tried quite a few things (single quotes, double quotes, groovy style string interpolation, passing as environment variable etc) except probably writing a simple shell script and invoking the command line inside it with params passed to the script which would probably be the closest to what happens when invoked directly from command line, but from all that I have tried nothing seems to work.
I am running Jenkins 2.375.2. Both controller and nodes run on Mac.
Will appreciate any suggestions.

Too many backslashes, should be:
sh '''mvn spring-boot:start \
exec:java \
-Dexec.classpathScope=test \
-Dexec.mainClass=io.cucumber.core.cli.Main \
-Dexec.args=\"src/test-bdd/resources/features/set02 --glue gluepackage\" \
spring-boot:stop
'''
btw, for this particular case I would recommend to define execution for exec-maven-plugin:
I. Java as executable (I prefer this option - it does not affect maven VM):
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>set02</id>
<phase>none</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>java</executable>
<arguments>
<argument>-classpath</argument>
<classpath />
<argument>io.cucumber.core.cli.Main</argument>
<argument>src/test-bdd/resources/features/set02</argument>
<argument>--glue</argument>
<argument>gluepackage</argument>
</arguments>
<classpathScope>test</classpathScope>
</configuration>
</execution>
</executions>
</plugin>
II. Main class within the same VM as maven:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>set02</id>
<phase>none</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<arguments>
<mainClass>io.cucumber.core.cli.Main</mainClass>
<argument>src/test-bdd/resources/features/set02</argument>
<argument>--glue</argument>
<argument>gluepackage</argument>
</arguments>
<classpathScope>test</classpathScope>
</configuration>
</execution>
</executions>
</plugin>
and run it via exec:exec#exection-id or exec:java#exection-id, i.e.:
sh '''mvn spring-boot:start \
exec:exec#set02 \
spring-boot:stop
'''
also, it is not clear whether maven can stop spring-boot application in case of failure and that is better to split pipeline into separate steps protected by try/finally.

Related

Is it possible to have two mainClass in the pom.xml or be able to run two classes in the same pom.xml?

I am working on a java project. We use Continuous Integration with maven 3, svn and Jenkins. We have one utility java project in which we've implemented some useful features. We build a jenkins tasks to run the mainClass in this project. Here is the code snippet on project pom.xml :
<plugin>
..
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.ent.uti.Cleaner</mainClass>
<arguments>
<argument>value1</argument>
<argument>value2</argument>
</arguments>
</configuration>
</plugin>
This class is execute in jenkins task configuration :
mvn exec:java -o -f cleaner/pom.xml
I am wondering if it is possible for me to implement some features in the same project and add another task in Jenkins ?
Is it possible to have two main classes in the same pom.xml configuration ?
I know i could create another project and configure a mainClass in the pom. I think doing so is not a good idea. The both task are independant so it's not suitable to run the both class one after another.
Thanks for reading.
You can use profiles for that purpose. All details are available here : http://www.jpeterson.com/2009/08/25/using-a-maven-profile-to-run-a-test-program/
Then your command line will look like :
mvn -P program1 exec:java -o -f cleaner/pom.xml
mvn -P program2 exec:java -o -f cleaner/pom.xml

SonarQube: Create HTML reports without run sonar:sonar command

In Sonar, we just download the sonar setup and if need, change the db credentials and run the command on maven project sonar:sonar, our coding stats and bugs are are analyzed by sonar and make the good html reports. But for this we need to run sonar:sonar command. Like findbugs, its possible to integrate with maven and create reports and time of maven:install .In this LINK at 4th step explain. Is also possible with sonar for make the report on maven:install command?
Like you can see on the SonarQube documentation, we strongly advise you to first run mvn clean install and then mvn sonar:sonar separately - otherwise you can have some side effects.
However, if you want to have all this in a single run, this is a Maven-related question. You just have to bind the "sonar" goal to the "install" phase in your POM, with something like:
...
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>sonar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
...

How to execute a third party jar using maven

I am using Liquibase (via its Maven plugin) to handle database migrations.
However not all Liquibase features are available via Maven. One in particular, Generate Changelog, is only available via the command line (using the downloadable liquibase.jar) with a command like this:
java -jar liquibase.jar \
--driver=oracle.jdbc.OracleDriver \
--classpath=\path\to\classes:jdbcdriver.jar \
--changeLogFile=com/example/db.changelog.xml \
--url="jdbc:oracle:thin:#localhost:1521:XE" \
--username=scott \
--password=tiger \
generateChangeLog
How can I execute this command via Maven, portably? That is, I do not want to have to add the liquibase.jar file to my project structure.
Instead, I would like to list it as a dependency (I could manually add the jar to my local repository or Nexus proxy) and then reference it when using something like the Exec Maven Plugin's exec:java or exec:exec goals, but I can't see how to do this using an executable jar with those goals. :(
Any suggestions would be much appreciated.
Thanks!
I don't know, but may be this will help you.
Try to use maven exec plugin and put as a mainClass configuration param this: liquibase.integration.commandline.Main
I get it from MANIFEST.MF from your jar file
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
...
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>liquibase.integration.commandline.Main</mainClass>
<arguments>
<argument>--driver=oracle.jdbc.OracleDriver</argument>
<argument>--changeLogFile=com/example/db.changelog.xml</argument>
...
</arguments>
</configuration>
</plugin>

How to use Maven classpath to run Java main class?

I'm currently using Maven to build my Rhino JavaScript project, download dependent libraries, and manage the classpath at runtime. I'm able to run the JavaScript entry point by using the Maven exec plugin, in the following way:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>org.mozilla.javascript.tools.shell.Main</mainClass>
<classpathScope>runtime</classpathScope>
<arguments>
<argument>path/to/entryPoint.js</argument>
</arguments>
</configuration>
</plugin>
This works well, but the problem is that maven takes about 10 seconds just to start, which is about 10 times longer than it takes my program to run. Is there a way to either:
improve the performance of the maven exec plugin so that it takes less time to start, or
export the classpath that maven would use at runtime, so that I can just start my program from a script?
You can use the -o / --offline switch to tell Maven to not bother checking for snapshot or plugin updates.
Use the appassembler or assembly plugins to generate startup scripts which will automatically (in the case of appassembler) reference the desired classpath.

Can Maven collect all the dependent JARs for a project to help with application deployment?

I'm just starting to use Maven, (evaluating it, really) and I need to be able to quickly generate a JAR file for my application and a directory with all the dependencies (for example, lib) so that I can deploy those two to be run in a stand-alone manner. Generating the JAR file with the proper manifest is easy, but I do not know how to get Maven to copy the dependencies for the current project into a lib directory that I can deploy.
Since this is for a stand-alone Java applications, I am not interested in deploying to a Maven repository, that is also fairly trivial, or at least easily googleable.
I've found out how to do everything except copy the dependent JAR files into some specified directory. This is the workflow I'm looking for:
$ mvn clean
$ mvn package
$ cp -r target/{lib,myApp.jar} installLocation
Then, running myApp.jar from installLocation as a JAR file should "just work" regardless of my $CLASSPATH.
To try and pre-empt some answers:
I do have a Main-class: set, and it works fine.
I've also set the classpath in the MANIFEST.MF, and that works fine too.
I've found out how to use <classpathPrefix> and <classpathMavenRepositoryLayout> to make this work -- but only on my machine. (via: <classpathPrefix>${settings.localRepository}</classpathPrefix>)
What you want to investigate is Maven's dependency plugin. Add something similar to the following to pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<configuration>
<outputDirectory>
${project.build.directory}
</outputDirectory>
</configuration>
</plugin>
Then run mvn clean dependency:copy-dependencies to copy perform the copy. Combine this with the assembly plugin and you can package everything into a self contained archive for distribution.
I did not care for the Shade plugin since it rolls all the packages from all the jars together.
To include all of the external libs you can use the Dependency Plugin as mentioned above.
This example will create a "lib" directory under "target/classes" before the "package" phase.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>target/classes/lib</outputDirectory>
<overWriteIfNewer>true</overWriteIfNewer>
<excludeGroupIds>
junit,org.hamcrest,org.mockito,org.powermock,${project.groupId}
</excludeGroupIds>
</configuration>
</execution>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>sources</goal>
</goals>
</execution>
</executions>
<configuration>
<verbose>true</verbose>
<detail>true</detail>
<outputDirectory>${project.build.directory}</outputDirectory>
</configuration>
</plugin>
Take a look at maven's dependency plugin, specifically the copy-dependencies goal. The usage section describes how to do exactly what you want.
To do it from the command line just do:
$ mvn dependency:copy-dependencies -DoutputDirectory=OUTPUT_DIR
Yet another one is appassembler plugin
What I like about it is that it packages the app in a form ready to use (with a .bat file ans such)
It sure can. You need to use the shade plugin which can be done by adding
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.3-SNAPSHOT</version>
<configuration>
<!-- put your configurations here -->
</configuration>
</plugin>
to your project.
Using maven.repo.local one can collect all jars, but, they are collected into a directory with maven hierarchy (.m2).
mvn install -Dmaven.repo.local=./pick/some/folder
You can then collect them (on Linux):
mkdir flat-repo
find ./pick/some/folder -type f -name "*.jar" | xargs -I'{}' cp '{}' flat-repo/

Categories

Resources