How to validate the output of grep in Jenkinsfile groovy - groovy

I am trying to run a command to retrieve the latest commit message in git and then do a grep to see if it contains certain string and then use that as a condition but getting errors.
def commitmsg = sh(returnStdout: true, script: "git log -1 --pretty='%s' | grep Merge").trim()
if (env.BRANCH_NAME == 'release' && commitmsg == 'Merge')
{
..........
}
How do i get this to work? I just want that if the output of
git log -1 --pretty='%s'
contains the string Merge then i can use it under if condition

I was able to get this to work.
def commitmsg = sh(returnStdout: true, script: "git log -1 --pretty='%s'").trim()
if (env.BRANCH_NAME == 'release' && commitmsg.contains("Merge pull request") == true)
{
....
}

Related

How to define a test stage in Jenkins pipeline which makes use of curl to check if the server is up or not?

I am using latest Jenkins in my Linux box.
I would like to implement a Test stage like below:
pipeline {
agent any
stages {
stage('Test') {
HTTP_CODE = sh (
script: 'echo $(curl --write-out \\"%{http_code}\\" --silent --output /dev/null http://localhost/)',
returnStdout: true
).trim()
}
}
}
In this stage, I want to execute a bash script to check whether the web server is up or not. HTTP_CODE variable will have the value 200 if everything is fine, and if there is any other value, then it can be treated as error.
How can I implement this logic as a testing stage in my Jenkins pipeline?
Thanks.
You should update your pipeline as follow:
pipeline {
agent any
stages {
stage('Test') {
HTTP_CODE = sh (
script: 'echo $(curl --write-out \\"%{http_code}\\" --silent --output /dev/null http://localhost/)',
returnStdout: true
).trim()
if ('200' != HTTP_CODE) {
currentBuild.result = "FAILURE"
error('Test stage failed!)
}
}
}
}
Regards.

replacing file variables by envsubst in jenkins pipeline

I want to replace some variables in a file having $variablename, at runtime from jenkins pipeline script. It seems envsubst is the best for my use case. When i execute by command line on linux server its working fine but when i'm executing through jenkins pipeline in sh script, nothing happens.
sonar-scanner.properties:
sonar.projectKey=Project:MavenTest$BRANCHNAME
sonar.projectName=MavenTest$BRANCHNAME
Example of Command line on linux box:
$ export BRANCHNAME=develop
$ envsubst '$BRANCHNAME'
Output:
sonar.projectKey=Project:MavenTestdevelop
sonar.projectName=MavenTestdevelop
But when i'm executing through jenkins file as a script, nothing is changed in file.
jenkins script:
node {
stage('checkout'){
checkout([$class: 'GitSCM', branches: [[name: ':^(?!origin/master$|origin/develop$).*']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'c0ce73db-3864-4360-9c17-d87caf8a9ea5', url: 'http://172.16.4.158:17990/scm/ctoo/testmaven.git']]])
}
stage('initialize variables'){
// Configuring BRANCH_NAME variable
sh 'git name-rev --name-only HEAD > GIT_BRANCH'
sh label: '', script: 'cut -d \'/\' -f 3 GIT_BRANCH > BRANCH'
branchname = readFile('BRANCH').trim()
env.BRANCHNAME = branchname
}
stage('build & SonarQube analysis') {
withSonarQubeEnv('Sonar') {
sh "envsubst '$BRANCHNAME' <sonar-scanner.properties"
}
}
}
Output:
[Pipeline] sh (hide)
envsubst repotest
sonar.projectKey=Project:MavenTest$BRANCHNAME
sonar.projectName=MavenTest$BRANCHNAME
Can someone please help me
Hi I don't have idea about the envbust but this can be achieved by passing sonar parameters via command line to the sonar see the below example:
withSonarQubeEnv('Sonar') {
sh "<sonarscanner path> -Dsonar.projectKey=Project:MavenTest$BRANCHNAME"
}
I had this problem and solved it by using his escape character
\,
for example:
sh "envsubst '\${SERVER_NAME}' < ./config/nginx/nginx.conf.template > ./config/nginx/nginx.conf"

Only build projects if something has changed

We want to split up our project into smaller pieces. Our current CI process goes through a short test phase and then runs a deployment script. However, if nothing has changed in one of the sub project, we do not want to go through the build for this.
Jenkins without pipelines supports exclusions in the SCM configuration (we use git) and based on this, you can configure a specific job to run. However, when using a pipeline, how can I know, if I should build this part or not? How do I get access to the paths that were affected by the last push?
At the moment our script is very simple, and we would like to keep it as simple as possible.
We were playing around with the scripted and the declarative syntax, but could not find a good solution.
Declarative:
#!groovy​
pipeline {
agent any
tools {
nodejs '8.1'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
# Only continue, if something has changed
stage('Install') {
steps {
sh 'npm install'
}
}
stage('Test') {
steps {
sh 'npm run test-jenkins'
}
post {
always {
junit "artifacts/test/report.xml"
}
}
}
}
}
Scripted:
#!groovy​
node {
def nodejs = tool name: '8.1', type: 'jenkins.plugins.nodejs.tools.NodeJSInstallation'
env.PATH = "${nodejs}/bin:${env.PATH}"
stage('Checkout') {
checkout scm
}
# Only continue, if something has changed
stage('Install') {
sh 'npm install'
}
stage('Test') {
try {
sh 'npm run test-jenkins'
} finally {
junit "artifacts/test/report.xml"
}
}
}
Thanks to ElpieKay's fast comment on my question, we now have an elegant solution:
Make a tag to the current commit on a successful build
In the next build compare the new commit and the tag for changes
We are using a multi-branch pipeline and a parallel build for the multiple projects we have under the same source root. We iterate through the projects (serviceX) and check in the corresponding directory for a change:
def projects = ['service1', 'service2']
def builders = [:]
for (p in projects) {
def label = p
builders[label] = {
def tag = "${BRANCH_NAME}_last"
node {
echo "Checking for changes compared to ${tag} in directory ${label}"
try {
sh "./check-for-changes ${tag} ${label}"
} catch (ignored) {
echo "Nothing to do"
return
}
dir (label) {
stage(label + ": Install") {
sh "npm install"
}
stage(label + ": Test") {
try {
sh "npm run test-jenkins"
} finally {
junit 'artifacts/test/report.xml'
}
}
echo "Setting tag for the last build on this branch"
sh "git tag -f ${tag}"
}
}
}
}
parallel builders
... and the script to check for changes:
#!/bin/bash
SHA_PREV=$1
if [ -z ${SHA_PREV} ]; then
echo "Usage: `basename $0` <tag> <path>"
exit 1
fi
CHECK_PATH=$2
if [ -z ${CHECK_PATH} ]; then
echo "Usage: `basename $0` <tag> <path>"
exit 1
fi
if `git rev-parse ${SHA_PREV} >/dev/null 2>&1`; then
echo "Found previous tag: ${SHA_PREV}"
else
SHA_PREV=`git rev-list --max-parents=0 HEAD`
echo "Using initial commit: ${SHA_PREV}"
fi
changes=`git diff --name-only ${SHA_PREV} HEAD | grep ${CHECK_PATH}/`
if [ ! -n "${changes}" ]; then
echo "No changes found"
exit 2 # no changes found
fi

Groovy: Seems like a scope issue but cannot find where, can you?

I wrote some functions to help me writing Jenkins pipelines.
The following functions, are responsible to returning a shell command output:
def gen_uuid(){
randomUUID() as String
}
def sh_out(cmd){
String uuid = gen_uuid()
sh """( ${cmd} )> ${uuid}"""
String out = readFile(uuid).trim()
sh "set +x ; rm ${uuid}"
return out
}
That shown, here's another function:
Map get_started_by(){
withCredentials([ // Use Jenkins credentials ID of artifactory
[$class: 'UsernamePasswordMultiBinding', credentialsId: '0b8d591a-f4ce-XXXX-XXXX-faecb504d3d0', usernameVariable: 'J_USER', passwordVariable: 'J_PASS'],
]){
List startedBy = sh_out("""
set +x; curl -u ${J_USER}:${J_PASS} '${env.BUILD_URL}api/json' 2>/dev/null | \
python -mjson.tool | \
awk -F'"' '/(userId|userName)/{print \$4}'
""").split(/(\n)/)
return [
userId: startedBy[0],
userName: startedBy[1]
]
}
}
Which returns the userId and userName of the user who issue the job run.
Then, my problem is in this function:
def run_in_stage_func(String stage_name, Closure command, String sendTo){
String started_by = get_started_by()
String ulink = "<#${started_by['userId']}>"
String jlink = "(<${env.BUILD_URL}|Open>)"
println "============================================================"
stage (stage_name) {
try {
command()
if (currentBuild.result == 'FAILURE') {
error "Build failed, see log for further details."
}
println "============================================================"
} catch (Exception ex) {
def except = "${ex}"
slackSend channel: channel, color: 'danger', teamDomain: null, token: null,
message: " :${ulink} *Failed to build ${env.JOB_NAME}*! :x: ${jlink} (<!here|here>)"
echo "Pipeline failed at stage: ${stage_name}"
throw ex
}
}
}
When I run the job, I get the following error:
groovy.lang.MissingPropertyException: No such property: userId for class: java.lang.String
What could be the reason that the line ' String ulink = "<#${started_by['userId']}>" ' - is not working as intended?
You cast the result of get_started_by() to String explicitly. To fix it, change your code to
def started_by = get_started_by()
or
Map started_by = get_started_by()

Multibranch Pipeline Jenkinsfile Looking for advice/Feedback

Ok, Below you find my opus.. (lol not really) but still this is my attempt to take a mess and automate it. Those who are willing, any advice would be appreciated.
The project all lives in one git repo. very much like https://github.com/jmvanryn/multibranchPipeline
some of my questions are..
could I be doing some of this better? how do I use Global variables?
you can see I'm defining some things twice. why does GIT pull twice?
is there a way to get the cobertura report plugin to work?
env.BRANCH_NAME gives me "feature/FeatureName" is there a
DSL/Groovy way to trim it to just FeatureName?
node {
wrap([$class: 'BuildUser']) {
def user = env.BUILD_USER_ID
}
env.JAVA_HOME = tool 'JDK1.7.0.21'
def mvnHome = tool 'M3'
def nodeJS = tool 'NodeJSv5.6.0'
env.MAVEN_OPTS = "-Xmx1024m -XX:MaxPermSize=512m"
env.PATH = "${mvnHome}/bin:${nodeJS}/bin:${env.JAVA_HOME}/bin:${env.PATH}"
//checkout scm
sh 'git rev-parse --verify HEAD > hash.txt'
env.GIT_COMMIT = readFile('hash.txt')
env.GIT_COMMIT = env.GIT_COMMIT.trim()
setVersion();
stage("Build Core")
hipchatSend color: 'GREEN', notify: true, room: '1654572'
BuildIt ("sharedLib1")
BuildIt ("sharedLib2")
stage("Build Modules")
parallel "first-ui": {
BuildIt ("first-ui")
}, "second-ui": {
BuildIt ("second-ui")
}, "first-ws": {
BuildIt ("first-ws")
}, "second-ws": {
BuildIt ("second-ws")
}
stage("Archive files")
echo("================================== Archive Stage ==================================")
step([$class: 'ArtifactArchiver', artifacts: '**/target/*.war', fingerprint: true])
//step([$class: 'ArtifactArchiver', artifacts: 'CONFIG/*.*', fingerprint: true])
step([$class: 'JUnitResultArchiver', testResults: '**/target/surefire-reports/TEST-*.xml'])
step([$class: 'hipchat', room: '1654572', startNotification: false, notifySuccess: true, notifyAborted: false, notifyNotBuil: false, notifyUnstable: false, notifyFailure: true, notifyBackToNormal: false])
stage("Notification")
step([$class: 'Mailer', notifyEveryUnstableBuild: true, recipients: 'jvanryn#liaison-intl.com', sendToIndividuals: true])
}
def BuildIt(module) {
sh "echo '================================== Build Stage : ${module} ==================================';\
cd ${module};\
mvn --batch-mode -V -U -e clean deploy -U -DskipITs sonar:sonar -Dsonar.branch=${env.BRANCH_NAME} -Dsurefire.useFile=false"
}
def setVersion () {
def JobCode = env.BRANCH_NAME
def JobName = env.JOB_NAME
def BuildURL = env.BUILD_URLD
def BuildNum = env.BUILD_NUMBER
def RevNum = env.GIT_COMMIT
def WrkSpce = pwd()
echo "Running Build for: "+JobCode
// update version to a unique version
def script=WrkSpce+"/Tools/PomVersionUpdater.sh "+JobCode+"-"+RevNum+"-"+BuildNum
sh script
}
First, you can create a .mvn folder with jvm.config and maven.config to store all those xmx parameters and others, so everyone is using the same build settings.
You also need a try/catch block to send some notification if the build fails.
Other than that it looks ok, could be better but it works

Resources