How do you extract a version number from nuspec into TeamCity? - teamcity

How do you extract a version number from nuspec into TeamCity?
We have a csproj file with this corresponding nuspec node:
1.3.2
In TeamCity I'd like to do a build of this project and create a NuGet package with version 1.3.2.%build.counter%. For example, 1.3.2.322. It is important the version number is coming from a file within source control (the NuSpec) and I don't want to duplicate this as a variable in TeamCity. Is there a way to extract 1.3.2 from the NuSpec file and use it as a TeamCity variable?

This approach works with version 10+ of TeamCity and gets around issues with Select-Xml and namespaces.
$Version = ([xml](Get-Content .\MyProject.nuspec)).package.metadata.version
$BuildCounter = %build.counter%
echo "##teamcity[setParameter name='PackageVersion' value='$Version.$BuildCounter']"

A couple of approaches I can think of spring to mind, both using TeamCity service messages:
Use a PowerShell build step, something like this (apologies my PS isn't great):
$buildcounter = %build.counter%
$node = Select-Xml -XPath "/package/metadata/version" -Path /path/to/nuspec.nuspec
$version = $node.Node.InnerText
Write-Output "##teamcity[buildNumber '$version.$buildcounter']"
Or, similarly, bootstrap a tool like XmlStarlet:
$buildcounter = "1231"
$version = xml sel -T -t -v "/package/metadata/version" Package.nuspec
Write-Output "##teamcity[buildNumber '$version.$buildcounter']"
This step would need to be added before any other step requiring the build number.

Related

How do I bump my project version on Gradle with a command similar to "npm version 1.5.0"?

I'm trying to develop an automation to bump projects versions using Jenkins. For node projects I've already implemented this automation with npm version {version}, but for gradle projects not yet. I just got the version on build.gradle with:
dir('examples/gradle'){
def version = sh(returnStdout: true, script: "cat build.gradle | grep -o 'project.version = [^,]*'").trim()
gradleProjectVersion = version.split(/=/)[1].trim()
}
Now I need to know a command similar to npm version {version} but for gradle so I can bump the project version with a value that I get in the name of my branch (and I already have the values that comes in the release branch).
I tried several commands I found here, my last attempt was:
dir('examples/gradle'){
docker.image('gradle:6.8-jdk11').inside('-v /gradle:/home/gradle/.gradle/caches'){
sh(script: "gradle -PprojVersion=${newProjectVersion}")
}
sh("git add .")
sh("git commit -m \"chore(build.gradle): bump version to ${newProjectVersion}\"")
}
but it isn't changing the project version.
I resolved this problem using "writeFile". Now my pipeline can override my project version from gradle. Here's the code that I used:
writeFile file: 'build.gradle', text: readFile('build.gradle').replaceAll(/project.version.*/, "project.version = \"${newProjectVersion}\"")

nuget modify text content file at installation

I'm writing a nuget package which deploys some content files.
I'd like them to be modified to contain the version number and install path.
I found this but it appears to modify only config and source files.
I noticed install.ps1 scripts, but they look only able to transform the target project and it's elements.
What if I want to add a text file to the project:
You just installed package $packageName version $version in $installPath
transformed after installation in
You just installed package myPackage version 1.0.12.12 in packages/myPackage-1.0.12.12
In fact install.ps1 script is run after the content files copy. And It's run after the content files have been appended to csproj:
Added file 'myfile.txt' to folder 'mypackage\content'.
Added file 'mypackage.nupkg' to folder 'mypackage'.
Successfully installed 'mypackage'.
Added file 'myfile.txt'.
Added file 'myfile.txt' to project 'myproject'
>> PowerShell scripts are being executed from 'tools' (not framework-specific)
Executing script file 'init.ps1`
That means, you can edit whatever your static files from that script (accessing them) from the $project parameter~:
param($installPath, $toolsPath, $package, $project)
$myFile = $project.ProjectItems.Item("myfile.txt")
$filePath = $myFile.Document.FullName
$content = Get-Content -Path "$filePath"
I don't know the canonical way to get the package version from this script, but it's part of the $installPath parameter.
Hope this will help someone

project version from maven to sonar using hudson

i am using maven2 , hudson and sonar
while doing sonar analysis - i would like some way to append the Hudson build# to the maven version of the project
The project version changes every 2 weeks - so take an example in the first 2 weeks :
<version>abc-SNAPSHOT</version>
after two weeks the next version could be something like :
<version>xyz-SNAPSHOT</version>
what I want is to append the build# to the version already present in pom - which is being picked up and passed to sonar
NOTE:
-Dsonar.projectVersion=xyz-SNAPSHOT-${BUILD_NUMBER}
Here - I am hardcoding the version and dynamically passing the build#
what I want is to be able to dynamically pick up the version from maven ( without changing it ) and simply appending the build# dynamically
any ideas of how this can be achieved ?
Thanks,
satish
You can use Groovy script to read the version and put on environment variable:
Getting Maven Version in Jenkins
I used this script on time to parse the version:
def project = new XmlParser().parse("/pom.xml")
def artifactId = project.artifactId.text().trim()
def version = project.version.text().trim()
println "ArtifactId: [" + artifactId + "]"
println "Version: [" + version + "]"
After set "Additional properties" field with:
-Dsonar.projectVersion=${MAVEN_VERSION}-${BUILD_NUMBER}
If Jenkins don't get the variable, try install:
https://wiki.jenkins-ci.org/display/JENKINS/EnvInject+Plugin
You can use this Jenkins feature: https://github.com/jenkinsci/jenkins/pull/933/files
Basically you can access env variables at build, mapped by Jenkins from Maven GAV info
POM_DISPLAYNAME
POM_DISPLAYNAME
POM_VERSION
POM_GROUPID
POM_ARTIFACTID
POM_PACKAGING
POM_RELATIVEPATH
This is not really a Sonar issue. It's Maven project versioning.
Snaphots are designed to be dynamic. You'll discover under the hood that Maven is saving time-stamped versions in your Maven repository (I don't know how these time-stamps could be passed onto Sonar, which perhaps is what you'd like). Snapshot builds are ideal for CI jobs. software that is never used by non-developers.
What's I'd recommend is either stop using snapshots (build a "release" each time), or just accept the fact that there are two kinds of build in Maven. My rule is that if the code is being used by others then it's no longer a snapshot and should be treated as a release. This creates challenges for emerging methodologies like continuous deployment..... If every build goes to production (or production copy) then snapshots become irrelevant.
Building a release everytime is not that bad. First of all naming convention, I'd recommend:
<major>.<minor>.<patch>.<hudson build num>
The Maven's release plugin will automate most of the pain in managing the details of the release (updating the POM, tagging your SCM system). Finally there is also a useful M2_Release plugin that enables you to trigger a release from Hudson GUI.
Thanks To Andre for pointing me to the other link
I did try it but was running into some issues as noted in the comments
Assuming what I have done is just a workaround and there is a better solution ?
( I am using Hudson )
So I defined a new Job in Hudson ( Build a Maven 2/3 project (Legacy) )
Here I defined a "Groovy PostBuild"
Copied the code in the link that Andre pointed me to :
import hudson.model.*;
import hudson.util.*;
def thr = Thread.currentThread();
def currentBuild = thr?.executable;
def mavenVer = currentBuild.getParent().getModules().toArray()[0].getVersion();
def newParamAction = new hudson.model.ParametersAction(new
hudson.model.StringParameterValue("MAVEN_VERSION", mavenVer));
currentBuild.addAction(newParamAction);
I then "Trigger parameterized build on other projects " and mentioned the job in which I wanted the maven version as mentioend in the pom
Defined a parameter - ${MAVEN_VERSION}
I was then able to get the value of this parameter in the "other" job
So first thanks to Andre - he provided me a solution
I am curious to know if this is a good approach
another question I have is ( which maybe I will start a new thread ) is - how does a Hudson "Free style" job differ from a "Maven 2/3 legacy project"
The reason I ask is the same Groovy script failed in a "free style" while it worked in a "Maven legacy"
Thanks,
satish
Had the same need and solved as suggested with Groovy parsing the pom.
import jenkins.util.*;
import jenkins.model.*;
def thr = Thread.currentThread();
def currentBuild = thr?.executable;
def workspace = currentBuild.getModuleRoot().absolutize().toString();
def project = new XmlSlurper().parse(new File("$workspace/pom.xml"))
def param = new hudson.model.StringParameterValue("project.version", project.version.toString())
currentBuild.addAction(new hudson.model.ParametersAction(param));
Add this script as a post step of type "Execute system Groovy script" (so it's not needed to install Groovy) and paste the code in the "Groovy command".

How to download the latest artifact from Artifactory repository?

I need the latest artifact (for example, a snapshot) from a repository in Artifactory. This artifact needs to be copied to a server (Linux) via a script.
What are my options? Something like Wget / SCP? And how do I get the path of the artifact?
I found some solutions which require Artifactory Pro. But I just have Artifactory, not Artifactory Pro.
Is it possible at all to download from Artifactory without the UI and not having the Pro-Version? What is the experience?
I'm on OpenSUSE 12.1 (x86_64) if that matters.
Something like the following bash script will retrieve the lastest com.company:artifact snapshot from the snapshot repo:
# Artifactory location
server=http://artifactory.company.com/artifactory
repo=snapshot
# Maven artifact location
name=artifact
artifact=com/company/$name
path=$server/$repo/$artifact
version=$(curl -s $path/maven-metadata.xml | grep latest | sed "s/.*<latest>\([^<]*\)<\/latest>.*/\1/")
build=$(curl -s $path/$version/maven-metadata.xml | grep '<value>' | head -1 | sed "s/.*<value>\([^<]*\)<\/value>.*/\1/")
jar=$name-$build.jar
url=$path/$version/$jar
# Download
echo $url
wget -q -N $url
It feels a bit dirty, yes, but it gets the job done.
Artifactory has a good extensive REST-API and almost anything that can be done in the UI (perhaps even more) can also be done using simple HTTP requests.
The feature that you mention - retrieving the latest artifact, does indeed require the Pro edition; but it can also be achieved with a bit of work on your side and a few basic scripts.
Option 1 - Search:
Perform a GAVC search on a set of group ID and artifact ID coordinates to retrieve all existing versions of that set; then you can use any version string comparison algorithm to determine the latest version.
Option 2 - the Maven way:
Artifactory generates a standard XML metadata that is to be consumed by Maven, because Maven is faced with the same problem - determining the latest version; The metadata lists all available versions of an artifact and is generated for every artifact level folder; with a simple GET request and some XML parsing, you can discover the latest version.
Using shell/unix tools
curl 'http://$artiserver/artifactory/api/storage/$repokey/$path/$version/?lastModified'
The above command responds with a JSON with two elements - "uri" and "lastModified"
Fetching the link in the uri returns another JSON which has the "downloadUri" of the artifact.
Fetch the link in the "downloadUri" and you have the latest artefact.
Using Jenkins Artifactory plugin
(Requires Pro) to resolve and download latest artifact, if Jenkins Artifactory plugin was used to publish to artifactory in another job:
Select Generic Artifactory Integration
Use Resolved Artifacts as
${repokey}:**/${component}*.jar;status=${STATUS}#${PUBLISH_BUILDJOB}#LATEST=>${targetDir}
You could also use Artifactory Query Language to get the latest artifact.
The following shell script is just an example. It uses 'items.find()' (which is available in the non-Pro version), e.g. items.find({ "repo": {"$eq":"my-repo"}, "name": {"$match" : "my-file*"}}) that searches for files that have a repository name equal to "my-repo" and match all files that start with "my-file". Then it uses the shell JSON parser ./jq to extract the latest file by sorting by the date field 'updated'. Finally it uses wget to download the artifact.
#!/bin/bash
# Artifactory settings
host="127.0.0.1"
username="downloader"
password="my-artifactory-token"
# Use Artifactory Query Language to get the latest scraper script (https://www.jfrog.com/confluence/display/RTF/Artifactory+Query+Language)
resultAsJson=$(curl -u$username:"$password" -X POST http://$host/artifactory/api/search/aql -H "content-type: text/plain" -d 'items.find({ "repo": {"$eq":"my-repo"}, "name": {"$match" : "my-file*"}})')
# Use ./jq to pars JSON
latestFile=$(echo $resultAsJson | jq -r '.results | sort_by(.updated) [-1].name')
# Download the latest scraper script
wget -N -P ./libs/ --user $username --password $password http://$host/artifactory/my-repo/$latestFile
You can use the REST-API's "Item last modified". From the docs, it retuns something like this:
GET /api/storage/libs-release-local/org/acme?lastModified
{
"uri": "http://localhost:8081/artifactory/api/storage/libs-release-local/org/acme/foo/1.0-SNAPSHOT/foo-1.0-SNAPSHOT.pom",
"lastModified": ISO8601
}
Example:
# Figure out the URL of the last item modified in a given folder/repo combination
url=$(curl \
-H 'X-JFrog-Art-Api: XXXXXXXXXXXXXXXXXXXX' \
'http://<artifactory-base-url>/api/storage/<repo>/<folder>?lastModified' | jq -r '.uri')
# Figure out the name of the downloaded file
downloaded_filename=$(echo "${url}" | sed -e 's|[^/]*/||g')
# Download the file
curl -L -O "${url}"
With recent versions of artifactory, you can query this through the api.
https://www.jfrog.com/confluence/display/RTF/Artifactory+REST+API#ArtifactoryRESTAPI-RetrieveLatestArtifact
If you have a maven artifact with 2 snapshots
name => 'com.acme.derp'
version => 0.1.0
repo name => 'foo'
snapshot 1 => derp-0.1.0-20161121.183847-3.jar
snapshot 2 => derp-0.1.0-20161122.00000-0.jar
Then the full paths would be
https://artifactory.example.com/artifactory/foo/com/acme/derp/0.1.0-SNAPSHOT/derp-0.1.0-20161121.183847-3.jar
and
https://artifactory.example.com/artifactory/foo/com/acme/derp/0.1.0-SNAPSHOT/derp-0.1.0-20161122.00000-0.jar
You would fetch the latest like so:
curl https://artifactory.example.com/artifactory/foo/com/acme/derp/0.1.0-SNAPSHOT/derp-0.1.0-SNAPSHOT.jar
The role of Artifactory is to provide files for Maven (as well as other build tools such as Ivy, Gradle or sbt). You can just use Maven together with the maven-dependency-plugin to copy the artifacts out. Here's a pom outline to start you off...
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>A group id</groupId>
<artifactId>An artifact id</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>The group id of your artifact</groupId>
<artifactId>The artifact id</artifactId>
<version>The snapshot version</version>
<type>Whatever the type is, for example, JAR</type>
<outputDirectory>Where you want the file to go</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Just run mvn install to do the copy.
You can use the wget --user=USER --password=PASSWORD .. command, but before you can do that, you must allow artifactory to force authentication, which can be done by unchecking the "Hide Existence of Unauthorized Resources" box at Security/General tab in artifactory admin panel. Otherwise artifactory sends a 404 page and wget can not authenticate to artifactory.
For me the easiest way was to read the last versions of the project with a combination of curl, grep, sort and tail.
My format: service-(version: 1.9.23)-(buildnumber)156.tar.gz
versionToDownload=$(curl -u$user:$password 'https://$artifactory/artifactory/$project/' | grep -o 'service-[^"]*.tar.gz' | sort | tail -1)
This may be new:
https://artifactory.example.com/artifactory/repo/com/example/foo/1.0.[RELEASE]/foo-1.0.[RELEASE].tgz
For loading module foo from example.com . Keep the [RELEASE] parts verbatim. This is mentioned in the docs but it's not made abundantly clear that you can actually put [RELEASE] into the URL (as opposed to a substitution pattern for the developer).
If you want to download the latest jar between 2 repositores, you can use this solution. I actually use it within my Jenkins pipeline, it works perfectly. Let's say you have a plugins-release-local and plugins-snapshot-local and you want to download the latest jar between these. Your shell script should look like this
NOTE : I use jfrog cli and it's configured with my Artifactory server.
Use case : Shell script
# your repo, you can change it then or pass an argument to the script
# repo = $1 this get the first arg passed to the script
repo=plugins-snapshot-local
# change this by your artifact path, or pass an argument $2
artifact=kshuttle/ifrs16
path=$repo/$artifact
echo $path
~/jfrog rt download --flat $path/maven-metadata.xml version/
version=$(cat version/maven-metadata.xml | grep latest | sed "s/.*<latest>\([^<]*\)<\/latest>.*/\1/")
echo "VERSION $version"
~/jfrog rt download --flat $path/$version/maven-metadata.xml build/
build=$(cat build/maven-metadata.xml | grep '<value>' | head -1 | sed "s/.*<value>\([^<]*\)<\/value>.*/\1/")
echo "BUILD $build"
# change this by your app name, or pass an argument $3
name=ifrs16
jar=$name-$build.jar
url=$path/$version/$jar
# Download
echo $url
~/jfrog rt download --flat $url
Use case : Jenkins Pipeline
def getLatestArtifact(repo, pkg, appName, configDir){
sh """
~/jfrog rt download --flat $repo/$pkg/maven-metadata.xml $configDir/version/
version=\$(cat $configDir/version/maven-metadata.xml | grep latest | sed "s/.*<latest>\\([^<]*\\)<\\/latest>.*/\\1/")
echo "VERSION \$version"
~/jfrog rt download --flat $repo/$pkg/\$version/maven-metadata.xml $configDir/build/
build=\$(cat $configDir/build/maven-metadata.xml | grep '<value>' | head -1 | sed "s/.*<value>\\([^<]*\\)<\\/value>.*/\\1/")
echo "BUILD \$build"
jar=$appName-\$build.jar
url=$repo/$pkg/\$version/\$jar
# Download
echo \$url
~/jfrog rt download --flat \$url
"""
}
def clearDir(dir){
sh """
rm -rf $dir/*
"""
}
node('mynode'){
stage('mysstage'){
def repos = ["plugins-snapshot-local","plugins-release-local"]
for (String repo in repos) {
getLatestArtifact(repo,"kshuttle/ifrs16","ifrs16","myConfigDir/")
}
//optional
clearDir("myConfigDir/")
}
}
This helps alot when you want to get the latest package between 1 or more repos. Hope it helps u too!
For more Jenkins scripted pipelines info, visit Jenkins docs.
With awk:
curl -sS http://the_repo/com/stackoverflow/the_artifact/maven-metadata.xml | grep latest | awk -F'<latest>' '{print $2}' | awk -F'</latest>' '{print $1}'
With sed:
curl -sS http://the_repo/com/stackoverflow/the_artifact/maven-metadata.xml | grep latest | sed 's:<latest>::' | sed 's:</latest>::'
In case you need to download an artifact in a Dockerfile, instead of using wget or curl or the likes you can simply use the 'ADD' directive:
ADD ${ARTIFACT_URL} /opt/app/app.jar
Of course, the tricky part is determining the ARTIFACT_URL, but there's enough about that in all the other answers.
However, Docker best practises strongly discourage using ADD for this purpose and recommend using wget or curl.
No one mention xmllint aka proper xml parser, install it with:
sudo apt-get update -qq
sudo apt-get install -y libxml2-utils
use it:
ART_URL="https://artifactory.internal.babycorp.com/artifactory/api-snapshot/com/babycorp/baby-app/CD-684-my-branch-SNAPSHOT"
ART_VERSION=`curl -s $ART_URL/maven-metadata.xml | xmllint --xpath '//snapshotVersion[1]/value/text()' -`
and finally:
curl -s -o baby-app.jar ${ART_URL}/baby-app-${ART_VERSION}.jar
or
wget ${ART_URL}/baby-app-${ART_VERSION}.jar
to keep the filename
If using the JFrog CLI, this can be done in a single line as follows:
jf rt dl "path/to/artifacts/-/" --sort-by=created --sort-order=desc --limit=1
(The above is for v2 but think the v1 command should be the same but substituting jf with jfrog.)

Getting Project Version from Maven POM in Jenkins

Is there any way a Jenkins build can be aware of the Maven version number of a project after processing the POM?
I've got some projects where versioning is controlled by Maven, and in a post-build job we'd like to create a Debian package and call some shell scripts. What I need is for the version number that Maven used to be available as a Jenkins environment variable so I can pass it to post-build actions.
To be clear, I'm not needing to know how to get Jenkins to pass a version number to Maven; instead I want Maven to pass a version number to Jenkins!
You can use the ${POM_VERSION} variable, which was introduced with https://issues.jenkins-ci.org/browse/JENKINS-18272
After a lot of digging around (I never realised how poorly-documented Jenkins is!) I found a quite trivial solution.
Install the Groovy plugin
Add a Post Step to your Maven build of type Execute **system** Groovy script
Paste in the following snippet of Groovy:
Script:
import hudson.model.*;
import hudson.util.*;
def thr = Thread.currentThread();
def currentBuild = thr?.executable;
def mavenVer = currentBuild.getParent().getModules().toArray()[0].getVersion();
def newParamAction = new hudson.model.ParametersAction(new hudson.model.StringParameterValue("MAVEN_VERSION", mavenVer));
currentBuild.addAction(newParamAction);
The build environment variable called MAVEN_VERSION will now be available for substitution into other post-build steps in the usual manner (${MAVEN_VERSION}). I'm using it for Git tagging amongst other things.
As other answers already pointed out, if you are using the Maven project type, you have access to the $POM_VERSION variable. But if you are not, you can use this sequence of steps (ugly but reliable). Doing it this way relies on the same version of maven to determine the pom version (while handling complex parent/child pom inheritance where <version> may not even be present for the child).
Maven step with this goal:
org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version -l version.log
Shell step: (You may need to adjust the path to version.log depending on your hierarchy)
echo "POM_VERSION=$(grep -v '\[' version.log)" > props.properties
Inject Environment Variables step (Environment Injector Plugin):
Properties File Path: props.properties
Now you can use $POM_VERSION as if this were a Maven project.
What this does: Uses maven to print out the version together with a mess of output, then greps out the mess of output leaving just the version, writes it to a file using properties file format and then injects it into the build environment. The reason this is better than a one-liner like mvn ..... | grep -v '\[' is that using a Maven step does not make assumptions about the installed maven versions and will be handled by the same auto-installation as any other maven steps.
I used Pipeline Utility Steps plugin in a declarative pipeline job to get Maven version. In the example below I use script variable instead of environment variable, because that can be modified and passed between stages.
def TAG_SELECTOR = "UNINTIALIZED"
pipeline {
agent any
stages {
stage('Build') {
steps {
sh "mvn --batch-mode -U deploy"
script {
TAG_SELECTOR = readMavenPom().getVersion()
}
echo("TAG_SELECTOR=${TAG_SELECTOR}")
}
}
}
}
Note: You must approve the getVersion() method after creating the job in Manage jenkins > In-process Script Approval.
See also:
readMavenPom documentation
We used the Groovy Postbuild Plugin.
String regex = '.*\\[INFO\\] Building .+ (.+)';
def matcher = manager.getLogMatcher(regex);
if (matcher == null) {
version = null;
} else {
version = matcher.group(1);
}
Adding this to Jenkins for use later is a bit tricky. Give this a shot, although I remember this causing us some headaches. (Sorry, we did this a long time ago)
def addBuildParameter(String key, String value) {
manager.build.addAction(new hudson.model.ParametersAction(new hudson.model.StringParameterValue(key,value)));
}
Had the same need and solved as suggested with Groovy parsing the pom.
import jenkins.util.*;
import jenkins.model.*;
def thr = Thread.currentThread();
def currentBuild = thr?.executable;
def workspace = currentBuild.getModuleRoot().absolutize().toString();
def project = new XmlSlurper().parse(new File("$workspace/pom.xml"))
def param = new hudson.model.StringParameterValue("project.version", project.version.toString())
currentBuild.addAction(new hudson.model.ParametersAction(param));
Add this script as a post step of type "Execute system Groovy script" (so it's not needed to install Groovy) and paste the code in the "Groovy command".
Execute the Maven Plugin "exec-maven-plugin" in "Execute Shell" as a "Conditional step" worked for me:
mvn -q -Dexec.executable="echo" -Dexec.args='${projects.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec
Integrate in Jenkins:
-> "Add post-build step"
-> "Conditional steps (single or multiple)"
-> "Execute Shell:"
export MY_POM_VERSION=`mvn -q -Dexec.executable="echo"
-Dexec.args='${projects.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` && [[
"${MY_POM_VERSION}" == "THE_VERSION_TO_BE_MATCHED" ]] && echo
"CONDITION_IS_MET"
-> "Steps to run if condition is met"
-> Add any build step you need
Notes:
THE_VERSION_TO_BE_MATCHED has to exchanged with your version
'&& echo "CONDITION_IS_MET"' is only for debugging purposes. For the same purpose you can add a '&& echo "MY_POM_VERSION=${MY_POM_VERSION}"' after the mvn command in order to understand what's going on.
This approach is more reliable than a "grep" and it could be an alternative if the Jenkins Ruby Plugin is not installed.
You could also do :
MAVEN_VERSION=`grep A -2 -B 2 "<your_project_name>" pom.xml | grep version | cut -d\> -f 2 | cut -d\< -f 1`-commit-"`echo $GIT_COMMIT`"
Explanation: assuming that you have your project name within a line or two above/below version like a normal pom:
<groupId>org.apache.bigtop</groupId>
<artifactId>bigpetstore</artifactId>
<version>1.0-SNAPSHOT</version>
Then you can easily grep for the artifactId, use the "before/after" grep actions to suck in the version with it, and then grep the version out and use the simple unix "cut" command to splice out the content between "version" tags.
I like the Jenkins-groovy integration, but this is alot easier and will work even on a build server which you dont have control over (i.e. because bash is universal).
Solution:
POM_VERSION=$( \
xmlstarlet sel \
-N x='http://maven.apache.org/POM/4.0.0' \
-t \
-v '//x:project/x:version/text()' \
pom.xml \
)
Explanation:
You can do this in a one-liner using a command-line XPath tool, such as those mentioned at "How to execute XPath one-liners from shell?". I chose XMLStarlet, but they all have similar syntax.
When parsing a POM, you have to account for namespaces. The docs here helped me figure this out.
In order to get the text for an element in XPath, you use the text() function as explained at XPath: select text node.
My POM looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.foo.bar</groupId>
<artifactId>foobar</artifactId>
<version>1.0.6-SNAPSHOT</version>
<packaging>jar</packaging>
The downside here is that if the namespace changes, you have to change the command.
Using 'Execute System Groovy Script' as follows:
import jenkins.util.*;
import jenkins.model.*;
def thr = Thread.currentThread();
def currentBuild = thr?.executable;
def projectManager = build.getProject()
def file = projectManager.getWorkspace().child("pom.xml");
def project = new XmlSlurper().parseText(file.readToString())
def param = new hudson.model.StringParameterValue("currentVersion", project.version.toString())
currentBuild.addAction(new hudson.model.ParametersAction(param));
By using Execute System Groovy script you have direct access to the build, from which you can get the project and thus the "child" file in this case pom.xml.
You won't have to create a new file and as you can see it offers very powerful access to every file within the workspace.
Based on #Akom`s answer the pre steps to have POM_VERSION are:
"Inject environment variables" with property
file your_property_file. Note if you select "Inject environment variables to the build process" the file needs to exist in the jenkins workspace.
run in a pre step execute shell the follwing
bash script.
Script
mvn org.apache.maven.plugins:maven-help-plugin:evaluate -Dexpression=project.version -l project_version
# grep for the version pattern rather than not mentioning '\['
echo "POM_VERSION=$(grep -E '^[0-9.]+(-SNAPSHOT)?$' project_version)" > your_property_file

Resources