Capturing the Unique Maven SNAPSHOT build number - maven-2

I am looking for a way to capture the unique SNAPSHOT build number that was generated during the 'mvn deploy' phase of the build. I would like to be able to pass this version (during a Hudson build) to another process used for deploying to an application server. The key here is being able to capture the exact Maven SNAPSHOT build number, such as:
foobar-0.4-20100707.060244-11.war
I have noticed that Hudson is capturing this information if you archive the maven build artifact, but it is not clear how I can expose this variable and pass it to another job (which is what I want to do). I can see this variable in the Hudson Home directory, like so:
/hudson/jobs/JOB_NAME/builds/24/org.ace.widgets$foobar/archive/org.ace.widgets/foobar/0.4-20100707.060244-11
Any Maven and/or Hudson experts out there that have any clue how to expose the SNAPSHOT build number? Hudson is doing it?

Check out my answer to this slightly different problem where I use GMaven to access the project metadata after deploy. What they have in common is that you have to access the unique build number. So you could adapt the script so that after it has read the project meta data (after deploy) it stores the unique version in the maven properties:
pom.properties['uniqueVersion'] = uniqueVersion
If the appserver-deploy-process is also a maven plugin, access this property, otherwise store it as a file using something like this:
new File(pom.build.directory, "uniqueVersion.txt").text = uniqueVersion
Now you can pick it up from target/uniqueVersion.txt using a shell script or so.

A little bit late, but I just noticed that you have exactly the same problem I was facing. I needed to be able to deploy arbitrary build artifacts produced on a Windows box on AIX machines. The deployment process needed to be run locally on the AIX boxes. So I defined slaves on the AIX boxes that download the build artifacts from the build job that run on the Windows box. The master is on the Windows box.
To put it in short. The build job archives the necessary artifacts and triggers the deployment job with its build URL as the parameter (it is actually a "run parameter", but string would work too). The deploy job uses wget to determine the artifact URL (it searches for a artifact ID that contains certain texts, e.g. the artifact name without the version), and downloads the artifact with wget again. wget saves it without version, so that all my deployment scripts can run on the unversioned name. You can use the first step also to find out about the artifact name as well.
wget uses the remote API (xml version). If you don't want to use wget, there is a command line tool that will do the connection for you.
You can test it by appending following strings to the run URL of the build job and use the resulting URL in your webbrowser.
#to find the path (URL) of the artifact
api/xml?xpath=*/artifact[contains(fileName,"MyApp")]/relativePath/text()
#to find the path (URL) of the artifact with more than 1 string to match
#the match must identify exactly one artifact, otherwise you will
#get an error message
api/xml?xpath=*/artifact[contains(fileName,"MyApp") and contains(fileName,".ear")]/relativePath/text()
#To download the artifact
#replace $relativePath with the actual output from one of the queries above
artifact/$relativePath

Based on Sean Patrick Floyds answer, even though this question is old, I'd like to share a full code example which writes the uniqueVersion into a maven property. Please keep in mind that Maven's internals are accessed using reflection, so this may easiliy breaks up in future maven versions. I tested it against Maven 3.2.5.
<build>
<plugins>
<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<executions>
<execution>
<id>set-uniqueVersion-property</id>
<phase>deploy</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
<![CDATA[
def uniqueVersion = null;
println "Grabbing uniqueVersion...";
project.artifact.metadataList.each{
if(it.class.simpleName=='ProjectArtifactMetadata'){
def afi = it.class.superclass.superclass.getDeclaredField('artifact');
afi.accessible = true;
uniqueVersion = it.artifact.version;
}
};
project.properties['uniqueVersion'] = uniqueVersion;
println("Unique Version grabbed: $uniqueVersion");
]]>
</source>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
If you want to use this property within other maven plugins, please make sure that their executions are made in the deploy phase after the set-uniqueVersion-property execution. If you prefer to write the unique version to a file, simply add
new File(pom.build.directory, "uniqueVersion.txt").text = uniqueVersion
as already stated by Sean Patrick.

Related

Arquillian Shrinkwrap provide custom settings.xml file

I have set up a arquillian project and it all works fine locally but when running the maven build on our continuous integration box it fails. I managed to get to the bottom of the problem and it is because the maven user settings.xml file on the CI box actually has some server definitions (for another project) whereas locally to my machine it is the default file (with no servers defined). The tests throw a RuntimeException because the MavenResolver goes looking for settings-security.xml file which doesn't exist on the CI box.
I would prefer not to go adding the settings-security.xml and instead would like to provide the resolver with a 'empty' settings.xml file, or even better, tell it not to use one. Is this possible?
I tried the answer from this thread https://developer.jboss.org/thread/174873 which pretty much says to add the following option to the failsafe plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.9</version><!-- or upper -->
<configuration>
<systemPropertyVariables>
<org.apache.maven.user-settings>nonExistentSetting.xml</org.apache.maven.user-settings>
</systemPropertyVariables>
</configuration>
</plugin>
If i do this and provide an xml file that doesnt exist all work fine from the command line running 'mvn clean install' but when i debug within my IDE it still fails.
Is there a way i can either:
Tell the maven resolver not to use a settings.xml / use a 'default' file
Create an empty settings.xml in my project and tell the maven resolver to use that
I did try the following line in my code to build my archive but it didnt seem to have an effect:
.addAsLibraries(Maven.configureResolver().fromFile("test-settings.xml").loadPomFromFile("pom.xml").importRuntimeDependencies().resolve().withTransitivity().asFile())
Thanks for any help,
Craig
ShrinkWrap resolver by default loads settings-security.xml from
DEFAULT_SETTINGS_SECURITY_PATH = userHome == null ? ".settings-security.xml" : userHome.concat("/.m2/settings-security.xml").replace('/', File.separatorChar);
but you can override this location by setting
System.setProperty(MavenSettingsBuilder.ALT_SECURITY_SETTINGS_XML_LOCATION,
"someDir/empty-settings-security.xml");
When alternative location (non-empty string) is provided theoretically it should skip the default location. However I am not 100% sure this method will work.

Attaching Build Number for binaries in Maven

I am running maven build and storing files in Artifactory. One issue I am facing is when ever I try a -snapshot version it overwrites the binary in Artifactory. I tried using the Maven build number plugin, but running in to issues.I reffered to this
http://blog.codehangover.com/track-every-build-number-with-maven/
Describing below What I did?
Updated the masterpom.xml with following line.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>1.0-beta-3</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
<configuration>
<doCheck>false</doCheck>
<doUpdate>false</doUpdate>
<format>${version}.{0,number}</format>
<items>
<item>buildNumber</item>
</items>
</configuration>
</plugin>
Now I update the pom of ear and webproject as below
<build>
<finalName>${project.artifactId}-${project.version}.${buildNumber}</finalName>
</build>
When I ran mvn clean install, ear and war got generated but when i checked the war inside the ear I am finding it as some thing like war-1.0-SNAPSHOT-null.war. I believe the war and ear couldn't get the buildNumber parameter. I was able to successfully generate the buildNUmber.property files and was able to increment the number by running the buildnumber:create plugin. Here are my questions
What I am doing wrong here and why the buildNumber parameter is not picked.
Also I want to generate all the binaries including jars in the following format binary-version-Snapshot.${buildNumber}. So Do i need to update pom of each file or any other way to update this?
Also we are using Hudson builds for Continous Integration and we want to separate developers builds with Hudson Build number. How can we achieve this if we don't want to checkin the buildNumber.properties after the Hudson build.
To get unique snapshots use the uniqueVersion flag (see James Lorenzen's Blog). If you use the maven goal deploy:deploy-file the uniqueVersion flag is true by default. At my company we have the following policy. Only "official" snapshots go to the repository. A "official" snapshot is one that was build on our reference system (our Jenkins ci server). We don't need the unique feature for snapshots, since we let Jenkins archive the artifacts. This way we can always go back to a certain version if we would like too by using Jenkins. If the build breaks the snapshot will not be deployed to the repo.
To your 2nd question; my understanding is that you need to update every pom file. But since it is a one time change, it shouldn't be too much of a burden.
I am not completely understanding your 3rd question ("... separate developers builds with Hudson Build number..."). In case you want to add the build number for every build done by Hudson, you have several options.
You can add a string as classifier while deploying. Maven will add that classifier in the filename (artifactID-version-classifier.jar - e.g. my.company.calendar-0.0.1-Snapshot-Hudson.jar). The artifact will be retrieved by adding the classifier to the dependency.
add another parameter to your maven call - outputfilename (${project.build.finalName}, see maven docu)
changing your version string to something like

Release problems with Nexus + Maven + Hudson

When using the release plug-in for Maven on Hudson(1.368), I am getting an error that my distributionManagement section is missing during the deployment phase to our Nexus Maven Repository Manager. If I deploy without using release It woks just fine so should not be a misconfiguration with the server, the section or the settings.
It is worth noting that my company uses different pom files for Hudson and have named them differently. Also the settings.xml in in the individual project directories. This has never been a problem as Hudson allows for the name of the pom and the location and name of the settings file to be specified.
The reason I note the above is that when distributionManagement is moved into the regular pom.xml it does find it (but still doesn't work because its missing the username and password in the settings file). This confuses the heck out of me since for the prior parts of the release process, it uses the correct pom and settings. It just seems to forget them later on. What is going on here?
Thank you in advance.
UPDATE
It seems that the maven release plug-in spins up a new instance of maven which, it seems, is using the default pom.xml rather than our differently named pom. More testing is needed.
The answer (for any lost souls who stumble upon this question) is that maven was indeed forking out a new process which was not using the correct pom file and settings. The solution was to add a section to the pom file as thus:
<plugin>
<artifactId>maven-release-plugin</artifactId>
<version>2.0</version>
<configuration>
<goals>-f POMFILE -s SETTINGSFILE deploy</goals>
</configuration>
</plugin>
This specified those two files to the new maven process.
If I deploy without using release It woks just fine so should not be a misconfiguration with the server, the section or the settings.
Well, there is clearly a misconfiguration somewhere, be it at the Hudson level. But it will be hard to spot it without seeing the pom, the settings, the active profiles, the profiles used during the release, the Hudson setup, etc.
First step: try to reproduce the problem on the command line using the exact same configuration as Hudson.
Second step: use the Maven Help Plugin to understand and debug the issue. More specifically, the following goals:
help:active-profiles
help:effective-pom
help:effective-settings
The reason I note the above is that when distributionManagement is moved into the regular pom.xml it does find it (but still doesn't work because its missing the username and password in the settings file).
It's unclear where the distributionManagement is specified if outside the project's pom.xml (in a corporate environment, it goes typically in a corporate pom.xml, is it the case here?).
It's also unclear if you are actually providing the username and password for a server id matching the repository id of the distributionManagement.
But somehow, a wrong combination is used here. Double check what profiles/settings are active during release/deploy to spot the problem as suggested.
See also
The Maven Deploy Plugin Usage page

Specifying jar file in maven build argument

We have our project build using maven. We try to run our unit test cases in maven build itself and for doing that we need to add DB2 driver jar in the dependency of all the sub projects.
Instead of doing that, we need a solution to specify the absolute path of the jar file as a mvn command line argument to use it in the running of unit test cases.
This is because the driver jar is available in our app server lib folder and we don't want to specify it in the dependencies of our projects.
Couldn't find a suitable solution googling it, hence requesting for an expert solution here.
Any workaround would be of greater help.
Thanks in advance.
The usual way would be to add a dependency to the database driver and limit the dependency to testing (test scope). So the library is available for unit tests but will not deployed and jar'ed.
Practically spoken, I'd create a maven artifact for this driver (just a basic POM file) and place it on the build servers maven repository (or the nexus, if you use it for the projects).
I'm using a dependency with scope set to 'system' to reference a jar that is available in the container but not in any maven repository. In this case the jar is put in a folder named 'lib' in the project like this, :
<dependency>
<groupId>groupId</groupId>
<artifactId>artifactId</artifactId>
<version>version</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/library.jar</systemPath>
</dependency>
The groupId, artifactId and version can be set to any value you want, the trick was that system dependencies have to be given with an absolute path, which is worked around by using the project.basedir property. It should also be possible to specify the complete path as a property.
We have our project build using maven. We try to run our unit test cases in maven build itself and for doing that we need to add DB2 driver jar in the dependency of all the sub projects.
Well, the maven way would be to declare the DB2 driver as dependency with a test scope in a parent project.
Instead of doing that, we need a solution to specify the absolute path of the jar file as a mvn command line argument to use it in the running of unit test cases.
You could use the additionalClasspathElement in the plugin configuration to pass the path to the driver:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<additionalClasspathElements>
<additionalClasspathElement>path/to/additional/resources</additionalClasspathElement>
</additionalClasspathElements>
</configuration>
</plugin>
If you variablelize it, you could pass the value on the command line.
But to be honest, I can't understand why you don't install the driver in a corporate repository and declare it as dependency. And if you don't have a corporate repository, use a file based repo as described in this previous answer (please, don't use the system scope bad practice). There is no good reason to go the hacky way.

using maven to manage java dependencies in a jruby rails app

I'm trying to write a pom.xml that will allow me to run a command locally and fetch all dependencies that my jruby Rails app has. I'm seeing two different configs though and I'm not totally sure which to use (as I'm not a java person whatsoever)
First, many Pom's i'm seeing just have a tag under the root of the pom.xml that list all dependencies. This doesn't however have any information about where these are stored etc... so I feel like this isn't what I want (I need to copy them to my rails lib dir)
Second option, I'm seeing in the mvn docs is to use the maven-dependency-plugin, which seems more like what i'm looking for. I assume then that my outputDirectory would be something like lib
So I don't fully understand what the purpose of the first option's dependency list is for. All I want is mvn to copy my jars locally (and then eventually when my CI server does a deploy). Can someone point me in the right direction?
First Option
<project>
<dependencies>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.4</version>
</dependency>
</project>
Second Option
<project>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<configuration>
<artifactItems>
<artifactItem>
<groupId>[ groupId ]</groupId>
<artifactId>[ artifactId ]</artifactId>
<version>[ version ]</version>
<type>[ packaging ]</type>
<classifier> [classifier - optional] </classifier>
<overWrite>[ true or false ]</overWrite>
<outputDirectory>[ output directory ]</outputDirectory>
<destFileName>[ filename ]</destFileName>
</artifactItem>
</artifactItems>
<!-- other configurations here -->
</configuration>
</plugin>
</plugins>
</build>
</project>
First, many Pom's i'm seeing just have a tag under the root of the pom.xml that list all dependencies. This doesn't however have any information about where these are stored etc... so I feel like this isn't what I want (I need to copy them to my rails lib dir)
This is the traditional way to declare and use dependencies on a Java project. Dependencies declared under the <dependencies> element are downloaded from a "remote repository" and installed to your "local repository" (in ~/.m2/repository by default) and artifacts are then handled from there. Maven projects (at least the Java ones) don't use a local lib/ folder for their dependencies.
Second option, I'm seeing in the mvn docs is to use the maven-dependency-plugin, which seems more like what i'm looking for. I assume then that my outputDirectory would be something like lib
The maven dependency plugin allows to interact with artifacts and to copy/unpack them from the local or remote repositories to a specified location. So it can be used to get some dependencies and copy them in lets say a lib/ directory indeed. Actually, it has several goals allowing to do this:
dependency:copy takes a list of artifacts defined in the plugin
configuration section and copies them
to a specified location, renaming them
or stripping the version if desired.
This goal can resolve the artifacts
from remote repositories if they don't
exist in local.
dependency:copy-dependencies takes the list of project direct
dependencies and optionally transitive
dependencies and copies them to a
specified location, stripping the
version if desired. This goal can also
be run from the command line.
The first goal would use the setup you described in your second option. The second goal would use the standard project dependencies that you described in your first option. Both approaches would work.
The problem here is that I don't know exactly what a JRuby Rails app is, what the development workflow is, how to build such an app, etc so I don't know exactly what you need to do and, consequently, what would be the best way to implement that with Maven.
So I googled a bit and found this post that shows another approach based on OS commands (using the maven exec plugin) and has a complete pom.xml doing some other things. Maybe you should look at it and use it as a starting point instead of reinventing everything. This is my suggestion actually.