Jenkins groovy pipeline search and compare - shell

I need a solution for the following to work - search for value variable BRANCHVERSION ​in ver_list, compare them and use an appropriate.
BRANCHVERSION has the format like this "6.200.01"​
​ver_list looks like this
[Pipeline] echo
[6.000.02, 6.000.10, 6.000.12, 6.000.15, 6.000.20, 6.000.25, 6.000.30, 6.100.00, 6.100.01, 6.100.10, 6.100.20, 6.100.25, 6.100.30, 6.200.00, 6.300.00]
if BRANCHVERSION is not equal to any values in ver_list, then​ the next closest value from the list ordered by descending must be picked up ( if BRANCHVERSION = 6.200.01, then 6.200.00 must be picked up)
if BRANCHVERSION is equal to any values in ver_list, then that value is picked up.
My pipeline described below:
if (ENVIRONMENT == "") {
error("You should choose at least one environment")
}
node {
deleteDir()
checkout([$class: 'SubversionSCM', locations: [[credentialsId: 'XXXXXXX',local: './env_prop_files', remote:'http://FQDN/repos/src/cm/env_prop_files']]])
checkout([$class: 'SubversionSCM', locations: [[credentialsId: 'XXXXXXX',local: './SoapUITestSuites', remote:'http://FQDN/repos/src/tools/SoapUI/branches/']]])
def FILES_LIST = sh (script: "ls './SoapUITestSuites'", returnStdout:true).trim()
def GS_LIST = sh (script: "ls 'path_to_file'", returnStdout: true).trim()
echo "GS_Version : ${GS_LIST}"
echo "FILES_LIST : ${FILES_LIST}"
//PARSING TestSuite Version
def ver_list = []
for(String ele : FILES_LIST.split("\\r?\\n")){
ver = ele.split("_")
println ">>>${ver[1]}<<<"
ver_list.add(ver[1])
}
println(ver_list)
def VERSION = ver_list
//PARSING GS Version
def gs_list = []
for(String elegs : GS_LIST.split("\\r?\\n")){
println ">>>${elegs}<<<"
gs_list.add(elegs)
}
println(gs_list)
properties = readProperties file:"./env_prop_files/${ENVIRONMENT}.properties"
BRANCHVERSION = properties.SVN_LOCATION_VERSION
}
OUTPUT
No changes for http://FQDN/repos/src/tools/SoapUI/branches since the previous
build
[Pipeline] sh
[ClientRunSoapUITest] Running shell script
+ ls ./SoapUITestSuites
[Pipeline] sh
[ClientRunSoapUITest] Running shell script
+ ls /pkg/flexprod/oracle/flexprodfiles/archive/goldstand
[Pipeline] echo
GS_Version : 5.900.00
6.000.00
6.000.01
6.000.02
6.000.20
6.000.30
6.100.00
6.100.01
6.200.00
[Pipeline] echo
FILES_LIST : rel_6.000.02
rel_6.000.10
rel_6.000.12
rel_6.000.15
rel_6.000.20
rel_6.000.25
rel_6.000.30
rel_6.100.00
rel_6.100.01
rel_6.100.10
rel_6.100.20
rel_6.100.25
rel_6.100.30
rel_6.200.00
rel_6.200.01
rel_6.300.00
[Pipeline] echo
>>>6.000.02<<<
[Pipeline] echo
>>>6.000.10<<<
[Pipeline] echo
>>>6.000.12<<<
[Pipeline] echo
>>>6.000.15<<<
[Pipeline] echo
>>>6.000.20<<<
[Pipeline] echo
>>>6.000.25<<<
[Pipeline] echo
>>>6.000.30<<<
[Pipeline] echo
>>>6.100.00<<<
[Pipeline] echo
>>>6.100.01<<<
[Pipeline] echo
>>>6.100.10<<<
[Pipeline] echo
>>>6.100.20<<<
[Pipeline] echo
>>>6.100.25<<<
[Pipeline] echo
>>>6.100.30<<<
[Pipeline] echo
>>>6.200.00<<<
[Pipeline] echo
>>>6.200.01<<<
[Pipeline] echo
>>>6.300.00<<<
[Pipeline] echo
[6.000.02, 6.000.10, 6.000.12, 6.000.15, 6.000.20, 6.000.25, 6.000.30, 6.100.00, 6.100.01, 6.100.10, 6.100.20, 6.100.25, 6.100.30, 6.200.00, 6.200.01, 6.300.00]
[Pipeline] echo
>>>5.900.00<<<
[Pipeline] echo
>>>6.000.00<<<
[Pipeline] echo
>>>6.000.01<<<
[Pipeline] echo
>>>6.000.02<<<
[Pipeline] echo
>>>6.000.20<<<
[Pipeline] echo
>>>6.000.30<<<
[Pipeline] echo
>>>6.100.00<<<
[Pipeline] echo
>>>6.100.01<<<
[Pipeline] echo
>>>6.200.00<<<
[Pipeline] echo
[5.900.00, 6.000.00, 6.000.01, 6.000.02, 6.000.20, 6.000.30, 6.100.00, 6.100.01, 6.200.00]
[Pipeline] readProperties
[Pipeline] }
[Pipeline] // node
[Pipeline] echo
"6.200.01"
[Pipeline] lock

First of all these are strings so you should change them to double. Much easier to compare them: 6.200.21 becomes 6200,21 (or 6200.21 depending on your localization)
Keep them in a list, it is much easier to work on them
The rest is simple Groovy List operations
BRANCH_VERSION = ver_list.contains(BRANCH_VERSION) ? BRANCH_VERSION : ver_list.max()
Of course if you need it as string then convert it back using the DecimalFormat Object and replace the commas with dots.

Related

sh command is not executing in jenkins pipeline project

While executing the sh command in jenkins pipeline project, we are getting an an error like below and sh command is not working.
Error message:
[Pipeline] sh
Warning: JENKINS-41339 probably bogus PATH=/bin/sh:/usr/atria/bin:/usr/atria/bin:$PATH; perhaps you meant to use ‘PATH+EXTRA=/something/bin’?
process apparently never started in /var/lib/jenkins/workspace/QSearch_pipelineTest#tmp/durable-6d5deef7
(running Jenkins temporarily with -Dorg.jenkinsci.plugins.durabletask.BourneShellScript.LAUNCH_DIAGNOSTICS=true might make the problem clearer)
[Pipeline] }
Below is the jenkins pipeline script code:
pipeline {
agent any
environment {
DATE = "December 17th"
}
stages {
stage("Env Variables") {
environment {
NAME = "Alex"
}
steps {
echo "Today is ${env.DATE}"
echo "My name ${env.NAME}"
echo "My path is ${env.PATH}"
script {
env.WEBSITE = "phoenixNAP KB"
env.PATH = "/bin/sh:$PATH"
}
echo "This is an example for ${env.WEBSITE}"
echo "My path ${env.PATH}"
**sh 'env'**
withEnv(["TEST_VARIABLE=TEST_VALUE"]) {
echo "The value of TEST_VARIABLE is ${env.TEST_VARIABLE}"
}
}
}
}
Below is the output of jenkins build job:
...
[Pipeline] echo
My path /bin/sh:/usr/atria/bin:/usr/atria/bin:$PATH
**[Pipeline] sh
Warning: JENKINS-41339 probably bogus PATH=/bin/sh:/usr/atria/bin:/usr/atria/bin:$PATH; perhaps you meant to use ‘PATH+EXTRA=/something/bin’?
process apparently never started in /var/lib/jenkins/workspace/QSearch_pipelineTest#tmp/durable-6d5deef7
(running Jenkins temporarily with -Dorg.jenkinsci.plugins.durabletask.BourneShellScript.LAUNCH_DIAGNOSTICS=true might make the problem clearer)**
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
**ERROR: script returned exit code -2**
Finished: FAILURE

Using variable as Jenkins input message text

i would like to use a variable as a message inside an input step inside a scripted pipeline.
stage("Manual Approval"){
sh """
ls -la
versionNumber=`grep -wE -A 2 '"package": "example0"'`
ancestorVersion=`grep -wE -A 2 '"package": "example"'`
"""
timeout(time: 120, unit: 'MINUTES') {
input message: "Do you want to build ver. ${versionNumber} having ver. ${ancestorVersion} as an ancestor?", submitter: 'user1'
}
}
In the latest version of the pipeline sh step allows save the output in a variable, following:
script {
INFO_SYSTEM = sh (
script: 'uname -a',
returnStdout: true
).trim()
echo "Value: ${INFO_SYSTEM}"
}
Output:
Running on Jenkins in /var/jenkins_home/workspace/testing
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Testing)
[Pipeline] script
[Pipeline] {
[Pipeline] sh
+ uname -a
[Pipeline] echo
Value: Linux d7d184735414 4.14.225-121.357.amzn1.x86_64 #1 SMP Mon Mar 15 23:52:05 UTC 2021 x86_64 GNU/Linux
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
So, maybe you can change the approach for do this task getting each variable in executing in a single command and retrieve the output, like this:
stage("Manual Approval"){
VERSION_NUMBER = sh (
script: 'grep -wE -A 2 '"package": "example0"'',
returnStdout: true
).trim()
ANCESTOR_VERSION = sh (
script: 'grep -wE -A 2 '"package": "example"'',
returnStdout: true
).trim()
timeout(time: 120, unit: 'MINUTES') {
input message: "Do you want to build ver. ${VERSION_NUMBER} having ver. ${ANCESTOR_VERSION} as an ancestor?", submitter: 'user1'
}
}

how to run jenkins declarative pipeline on node selected via parameter and label option

I want to run a pipeline with the node set as parameter via the Node and Label plugin.
How do I change the declarative pipeline
pipeline {
agent {
label 'whatever'
}
...
to use EXECUTION_NODE as agent to execute the pipeline? This seems to be much more complicated than I thought, or I am missing something obvious.
The issue is this: to present you the "Build with parameters" page, Jenkins needs to run your pipeline and parse its parameters. To run a pipeline, Jenkins needs a node. To have a node, it parses your pipeline. So the node is already selected by the time the dialog is shown. Moreover, in declarative pipeline all the nodes of all the stages get selected in the beginning.
You can try running a scripted pipeline or a combination of scripted and declarative, by running node and supplying params.EXECUTION_NODE as label. Scripted pipeline executes the script line by line.
Edit: this is working:
NODE = null
echo "This should be Null: $NODE"
node() {
stage("Define node") {
NODE = params.NODE
echo "This is now $NODE"
}
}
pipeline {
agent { node { label "$NODE" }}
parameters { string(name: 'NODE', defaultValue: 'some_node', description: '') }
stages {
stage("Main") {
steps {
echo "Hi"
}
}
}
}
Here is an output of a second run with 'master' as parameter:
Started by user marat
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] echo
This should be Null: null
[Pipeline] node
Running on Jenkins in /home/jenkins/workspace/test
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Define node)
[Pipeline] echo
This is now master
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] node
Running on master in /var/jenkins_home/workspace/test
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Main)
[Pipeline] echo
Hi
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

Why is Jenkins pipeline returning -#tmp/durable-56090643/script.sh 4: FSUM7728 bad ${} modifier for shell command?

I have this stage in my Jenkins pipeline that runs a command and stores the output in a variable. I'm trying to get the id number from the stored string but getting the error bad ${} modifier. Should have printed 00062100. It works correctly in the console.
stage('test') {
agent {node 'test'}
steps{
sh "string=$(onetstat -a -P 1111)"
sh "echo ${string:6:8}"
}
}
output from the command("BUILD 00062100 Listen")
**Update:**
stage('server2') {
agent {node 'test'}
steps{
sh '''
var="$(onetstat -a -P 1111)"
echo ${var:6:8}
'''
}
}
**log of the run**
[Pipeline] sh
+ + onetstat -a -P 1111
+ 1<TMP> /tmp/shGgcEdAGgA
var=
BUILDER8 00069B50 Listen
Local Socket: 127.0.0.1..1111
Foreign Socket: 0.0.0.0..0
/Build#tmp/durable-a93a2921/script.sh 3: FSUM7728 bad ${} modifier
There are two misunderstandings in your example. When you use double quotes in the Jenkinsfile, you construct a Groovy String that substitutes variables (defined using $ sign) with associated values (or expressions.)
Another misunderstanding is creating a bash variable in one sh step and accessing it in another sh step. It won't work that way. Each sh step runs in its own shell process, and any local variable created in one shell cannot be accessed in another.
You can solve both issues. Firstly, you need to replace double quotes with single quotes in sh step. Secondly, you need to define shell script in a single sh step. You can use Groovy multiline string for that (triple quotes.) Consider the following example:
pipeline {
agent any
stages {
stage("Test") {
steps {
// Below code prints nothing
sh 'something="BUILD 00062100 Listen"'
sh 'echo ${something:6:8}'
// Below code prints 00062100
sh '''
something="BUILD 00062100 Listen"
echo ${something:6:8}
'''
}
}
}
}
Output:
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Test)
[Pipeline] sh
+ something='BUILD 00062100 Listen'
[Pipeline] sh
+ echo
[Pipeline] sh
+ something='BUILD 00062100 Listen'
+ echo 00062100
00062100
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
Used this solution to get the id from the command output
var=$(onetstat -a -P 1111)
var=$(echo $var | cut -b 6-10)

Multiple variables in Jenkins shell

I try to print two variables in Jenkins shell (one of which is global one) . When I print them independently on shell for each it works, however when I try both variables on single line it fails. See the output, seems like a crop after the first variable .
I've tried to print two local variables, and it seems working. However I need the global one
#!/usr/bin/env groovy
def START
node ('master') {
// options{
// timestamps()
// }
stage("one") {
script{
START = sh(script: 'date --utc +%FT%T', returnStdout: true)
}
stage("two") {
def END = sh(script: 'date --utc +%FT%T', returnStdout: true)
sh "echo start $START"
sh "echo end $END"
sh "echo $START and $END"
}
}
}
+ date --utc +%FT%T
[Pipeline] sh
+ echo start 2019-08-01T14:48:08
start 2019-08-01T14:48:08
[Pipeline] sh
+ echo end 2019-08-01T14:48:09
end 2019-08-01T14:48:09
[Pipeline] sh
+ echo 2019-08-01T14:48:08
2019-08-01T14:48:08
+ and 2019-08-01T14:48:09
/var/jenkins_home#tmp/durable-979e1b9e/script.sh: 2: /var/jenkins_home#tmp/durable-979e1b9e/script.sh: and: not found
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
ERROR: script returned exit code 127
Finished: FAILURE
sh is a dedicated command of jenkins-groovy. The first two work because $START/$END are the final string and doesn't try to replace something else.
sh "echo ${START} and ${END}" writing the variables like this will limit the GString and convert only the correct part and wont try to convert the "and" also.
For more have a look at this examples http://grails.asia/groovy-gstring-examples

Resources