We want to define the project version for our Gradle project during the build of our project in the Jenkins pipeline, which will include a timestamp and a git-commit-id. (20180625180158-b8ad8df0dc0356a91707eaa241de7d62df6a29f2)
void defineVersion() {
sh "git rev-parse HEAD > .git/commit-id"
commitId = readFile('.git/commit-id')
timestamp = getCurrentTimestamp()
version = timestamp+'-'+commitId
}
This function will determine the version I want to publish our artifact with.
Next I use the Artifactory Gradle plugin to publish, but I can't find a way to set/override the project version. I want the jar to be published with version 20180625180158-b8ad8df0dc0356a91707eaa241de7d62df6a29f2
version = defineVersion() // how can we incorperate this version in our gradle build/publish?
gradleBuild = Artifactory.newGradleBuild()
gradleBuild.useWrapper = true
gradleBuild.deployer(
repo: env.BRANCH_NAME == 'master' ? 'libs-releases-local' : 'libs-snapshots-local',
server: Artifactory.server('artifactory-global'))
gradleBuild.run tasks: 'clean build artifactoryPublish'
How can we achieve this? Also I would like to pass other parameters like -x test to the run command to skip tests in this stage.
Apparently you can add parameters throug the switches parameter: https://jenkins.io/doc/pipeline/steps/artifactory/
With this you add the necessary parameters like '-x test -Pversion=' + version
For my use case I added a version property to my build.gradle: version = "${version}" so it can be overridden with the command above.
Related
I googled for ages now and I give up, the buzz word Groovy + Jenkins is bringing up so many false flags...
I have a Groovy project I developed in IntelliJ, it contains also a JUnit.groovy with unit tests. Now this is a script for SoapUI, no need for Maven, Ant nor Grails, but I would like to be able to compile those files on Jenkins and run the unit tests after. Is it possible to build and test those files on Jenkins? So far all solutions seem to be me manually running groovyc (commited with my repository) and then running JUnit on the JUnit.class.
So before I start to dig deeper and write a Maven, Grails or Ant file, is there another way that does not involve me pushing the GroovySDK on my git? Or is there may be a simple build script, not involving 20 libraries and steps that would build the groovy sources and run the JUnit tests :) ?
I'm new to Jenkins obviously ;), thanks for your input.
Update:
So for all as newbie as me, what was required? First I changed my local source code to a gradle project (remember to activate AutoImport in IntelliJ) and also activate the creation of the JUnit xml and since I do not use Maven and the system is "offline" we have the libs in git anyway so my build.gradle is:
version '2.5-SNAPSHOT'
apply plugin: 'groovy'
dependencies {
compile fileTree(dir: '../Library', include: ['*.jar'])
}
test {
reports {
junitXml.enabled = true
html.enabled = true
}
}
sourceCompatibility = 1.8
set up gradle wrapper for the project via gradle wrapper for the gradlew.bat
then I added a post-commit in my git-/.hooks/ so my Jenkins is triggered upon commit via curl http://jenkins:8080/git/notifyCommit?url=https://git.git&branches=dev
finally set up a pipeline on jenkins:
#!groovy
node {
stage('Checkout') {
git branch: 'dev', credentialsId: 'youwish', url: 'https://git.git'
}
stage('Build') {
dir('./Modules') {
gradle('clean')
gradle('compileTestGroovy')
}
}
stage('UnitTest') {
dir('./Modules') {
gradle('test')
junit '/build/test-results/**/TEST-*.xml'
}
}
stage('IntegrationTest') {
stage('CodeTableDownload') {
dir('./SoapUi') {
bat 'AutoRun.bat'
junit '/results/**/*-JUNIT.xml'
}
}
}
}
def gradle(command) {
bat "./gradlew.bat $command"
}
There's a Groovy plugin for Jenkins that will let you execute Groovy scripts on Jenkins.
But, why not let something like Gradle do the build and run the test for you? A minimal Gradle build file for Groovy that will do both is:
apply plugin: 'groovy'
repositories {
jcenter()
}
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.4.12'
testCompile 'junit:junit:4.12'
}
You don't have to commit the GDK, just declare a dependency.
I'm trying to set up a jenkins pipeline for publishing a zip file to jfrog artifactory.
I am using com.jfrog.artifactory plugin to do so. This works great from command line gradle and I can run the artifactoryPublish task to publish the artifacts and tie them back to the module, which then has a tie back to the artifacts.
The artifacts show up with the properties:
build.name = `projectname`
build.number = `some large number`
And I can click from them to the build/module and back to the artifact.
However, when I run this from a jenkinsfile pipeline, the artifacts get published and get tied back to the module, but then the module does not successfully tie the module back to the artifacts.
The artifacts do not receives the build.name and build.number properties and i cannot click from the module back to the artifacts, as the module cannot find or resolve the paths back to the artifacts(a zip file and a generated pom).
I am passing the params from jenkins like:
ORG_GRADLE_PROJECT_buildInfo.build.number=${env.BUILD_NUMBER} which seems to work on other projects... but for whatever reason I cannot shake it.
I can include more jenkinsfile if that would help debug, but i'm really just checking out a repository and trying to publish it.
I have been reading heavily the documentation here:
https://www.jfrog.com/confluence/display/RTF/Gradle+Artifactory+Plugin
and haven't been able to make it work through -Pproject stuff.
Does anyone have any idea what else I can try? i don't really want to use the jenkins pipeline artifactory plugin directly because it's so nice to be able to deploy from the command line too.
build.gradle:
publishing {
publications {
ManualUpdaterPackage(MavenPublication){
artifact assembleManualUpdaterPackage
}
}
}
artifactory {
contextUrl = "${artifactoryUrl}" //The base Artifactory URL if not overridden by the publisher/resolver
publish {
defaults {
publications('ManualUpdaterPackage')
}
repository {
repoKey = project.version.endsWith('-SNAPSHOT') ? snapshotRepo : releaseRepo
username = "${artifactory_user}"
password = "${artifactory_password}"
maven = true
}
}
}
task assembleManualUpdaterPackage (type: Zip){
dependsOn anotherTask
from (packageDir + "/")
include '**'
// archiveName "manualUpdaterPackage-${version}.zip"
destinationDir(file(manualUpdaterZipDir))
}
jenkinsfile snip:
withCredentials(
[
[
$class : 'UsernamePasswordMultiBinding',
credentialsId : 'validcreds',
passwordVariable: 'ORG_GRADLE_PROJECT_artifactory_password',
usernameVariable: 'ORG_GRADLE_PROJECT_artifactory_user'
]
]
) {
withEnv(
[
"ORG_GRADLE_PROJECT_buildInfo.build.number=${env.BUILD_NUMBER}",
"ORG_GRADLE_PROJECT_buildInfo.build.name=${artifactName}",
"ORG_GRADLE_PROJECT_buildInfo.build.url=${env.JOB_URL}"
]
) {
sh 'chmod +x gradlew'
sh "./gradlew --no-daemon clean artifactoryPublish"
}
}
https://www.jfrog.com/confluence/display/RTF/Working+With+Pipeline+Jobs+in+Jenkins#WorkingWithPipelineJobsinJenkins-GradleBuildswithArtifactory
Eventually my coworker recommended looking into the Artifactory Pipeline Gradle plugin instead. It is very nice to work with and we've had much quicker success with it.
In gradle I'd like to add both the current branch-name and commit-number as suffix to my versionName. (Why? Because when I build my app in Jenkins to release it in HockeyApp, it's useful to show what branch & commit that app was built from!)
So when I enter this in command prompt, my current branch name is returned:
git rev-parse --abbrev-ref HEAD
Same happens when I use this line in Android gradle, using the code in either this answer, or as shown in this piece of gradle code:
def getVersionNameSuffix = { ->
def branch = new ByteArrayOutputStream()
exec {
// The command line to request the current branch:
commandLine 'git', 'rev-parse', '--abbrev-ref', 'HEAD'
standardOutput = branch
}
println "My current branch: " + branch
def versionNameSuffix = "-" + branch
// ... some other suffix additions ...
return versionNameSuffix
}
buildTypes {
debug {
applicationIdSuffix ".test"
versionNameSuffix getVersionNameSuffix()
}
}
Resulting log (this is exactly what I want):
"My current branch: feature/MyFeature"
However, when I build my app in a Jenkins job, it will output a different result:
"My current branch: HEAD"
Why does this happen, and how to correctly retrieve my current branch name in Jenkins?
EDIT:
I've used a different approach, which returns the branchName correctly in most cases, also on Jenkins:
git name-rev --name-only HEAD
Example output in prompt:
"My current branch: feature/MyFeature"
Example output in Jenkins:
"My current branch: remotes/origin/feature/MyFeature"
I can remove "remotes/origin/" if i like, so that's okay!
But this approach causes different trouble (both in prompt, gradle and on Jenkins). When I have tagged the last commit, it won't output the branch-name, but this:
"My current branch: tags/MyTag^0"
EDIT 2:
A third approach can be found here.
Including the comments below the answer, I could use grep * to retrieve the branch in prompt. However, I cannot use the backslash in the gradle code. This fails:
commandLine 'git', 'branch', '|', 'grep', '\\*'
Any advice?
Try the env: BRANCH_NAME
BRANCH_NAME
For a multibranch project, this will be set to the name of the branch being built, for example in case you wish to deploy to production from master but not from feature branches.
Access it with env.BRANCH_NAME
I'm trying to migrate my build pipelines to the "Pipeline plugin" using the groovy build scripts.
My pipelines are usually:
Test (gradle)
IntegrationTest (gradle)
Build (gradle)
Publish (artifactory)
I would like to use the gradle variables like version/group etc. in my jenkins build script to publish to the correct folders in artifactory. Something the artifactory plugin would take care of for me in the past. How can this be achieved?
For a single gradle project I use something like this:
node('master')
{
def version = 1.0
def gitUrl = 'some.git'
def projectRoot = ""
def group = "dashboard/frontend/"
def artifactName = "dashboard_ui"
def artifactRepo = "ext-release-local"
stage "git"
git branch: 'develop', poll: true, url: "${gitUrl}"
dir(projectRoot)
{
sh 'chmod +x gradlew'
stage "test"
sh './gradlew clean test'
stage "build"
sh './gradlew build createPom'
stage "artifact"
def server = Artifactory.server('artifactory_dev01')
def uploadSpec = """{
"files": [
{
"pattern": "build/**.jar",
"target": "${artifactRepo}/$group/${artifactName}/${version}/${artifactName}-${version}.jar"
},
{
"pattern": "pom.xml",
"target": "${artifactRepo}/$group/${artifactName}/${version}/${artifactName}.pom"
}
]
}"""
def buildInfo1 = server.upload spec: uploadSpec
server.publishBuildInfo buildInfo1
}
}
For future reference here an example with the more modern declarative pipeline:
pipeline {
agent any
stages {
stage('somestage') {
steps {
script {
def version = sh (
script: "./gradlew properties -q | grep \"version:\" | awk '{print \$2}'",
returnStdout: true
).trim()
sh "echo Building project in version: $version"
}
}
}
}
}
see also:
Gradle plugin project version number
How to do I get the output of a shell command executed using into a variable from Jenkinsfile (groovy)?
I think you actually have two different approaches to tackle this problem :
1. Get version/group from sh script
Find a way to get Gradle version from gradle build tool (e.g. gradle getVersion(), but I'm not familiar with Gradle) and then use shell script to get this version. If Gradle command to get the version is gradle getVersion(), you would do in your pipeline :
def projectVersion = sh script: "gradle getVersion()", returnStdout: true
def projectGroup= sh script: "gradle getGroup()", returnStdout: true
and then just inject your $projectVersion and $projectGroup variables in your current pipeline.
2. Configure your Gradle build script to publish to Artifactory
This is the reverse approach, which I personnaly prefer : instead of giving Artifactory all your Gradle project information, juste give Gradle your Artifactory settings and use Gradle goal to easily publish to Artifactory.
JFrog has a good documentation for this solution in their Working with Gradle section. Basically, you will follow the following steps :
Generate a compliant Gradle build script from Artifactory using Gradle Build Script Generator and include it to your project build script
Use Gradle goal gradle artifactoryPublish to simply publish your current artifact to Artifactory
For others who Google'd their way here, if you have the Pipeline Utility Steps plugin and store what you need in your gradle.properties file, you can do something like this in the environment block:
MY_PROPS = readProperties file:"${WORKSPACE}/gradle.properties"
MY_VERSION = MY_PROPS['version']
I have two jenkins jobs:
build the project
deploy it
Both are working well and I can trigger the deploy job from the project build job.
Steps:
Build with parameters in the application's job >> check deploy on dev >> build
Add a yellow star badge to the build history in the application job - with groovy post-build action (code below)
Trigger the deploy job as post-build action
Question
After the deploy job was finished and failed change the build history of the application job (yellow star >> eg red one) - from the deploy job. How can I do that?
if ("true".equals(manager.build.buildVariables.get('DEPLOY_ON_DEV'))) {
manager.addBadge("star-gold.gif", "SNAPSHOT deployed on DEV")
}
This took me a while to develop but now it works like a charm in Post-build Actions → Add post-build action → Groovy Postbuild → Groovy script:
import hudson.model.Build
import hudson.model.Cause
import hudson.model.Project
import jenkins.model.Jenkins
import org.jvnet.hudson.plugins.groovypostbuild.GroovyPostbuildAction
def log = manager.listener.logger
log.println(' ----------------')
log.println(' Groovy Postbuild')
// decorate this build
manager.addShortText('SNAPSHOT deployed on DEV', 'black', 'gold', '1px', 'black')
manager.addInfoBadge('SNAPSHOT deployed on DEV')
manager.addBadge('star-gold.png', 'SNAPSHOT deployed on DEV')
// decorate upstream builds
Jenkins jenkins = Jenkins.getInstance()
List<Project> projects = jenkins.getAllItems(Project.class)
log.println(" This build: '${manager.build}' --> " + manager.build.getResult())
log.println(' Decorating the following upstream builds:')
//log.println(manager.build.getUpstreamBuilds()) // prints "[:]", so using this to get the upstream Builds doesn't work
for (Cause cause : manager.build.getCauses()) {
for (Project project : projects) {
if (cause.toString().contains(project.getName())) {
int no = cause.getUpstreamBuild()
Build usb = project.getBuildByNumber(no)
log.println(" ${usb}")
usb.getActions().add(GroovyPostbuildAction.createShortText(
'SNAPSHOT deployed on DEV', 'black', 'gold', '1px', 'black'));
usb.getActions().add(GroovyPostbuildAction.createInfoBadge(
'SNAPSHOT deployed on DEV'))
usb.getActions().add(GroovyPostbuildAction.createBadge(
'star-gold.png', 'SNAPSHOT deployed on DEV'))
}
} // for (projects)
} // for (causes)
log.println(' ----------------')
Note:
This adds badges regardless of the build result but I'm confident that you can add the appropriate if easily. For removing badges see Groovy Postbuild Plugin's page.
References:
Jenkins set a badge as a pre-build step
Jenkins main module 1.622 API
Groovy Postbuild Plugin
GroovyPostbuildAction.java