How to compare 2 parameters in Jenkins pipeline? - jenkins

I have 2 string parameters 1) filename 2) Path
filename - sample.txt
path - /usr/cole/jenkins/1240/hd/sample.txt
I want to compare if the "Path" has "Filename" in it and then perform some action if the condition is true
def matchpat = ('${params.path}' =~ /${params.filename}/)
print matchpat
assert params.filename == matchpat[0]
But it doesn't work

In this case you could use String.endsWith(str) method like:
def path = '/usr/cole/jenkins/1240/hd/sample.txt'
def filename = 'sample.txt'
if (path.endsWith(filename)) {
println 'Performing some action...'
}
Running this script produces as expected:
Performing some action...

Related

Jenkins: Set job timeout from a variable in scripted pipeline

I premise that I am not very familiar with Jenkins and Groovy.
I am trying to set a timeout with a time value that can change based on a specific condition. I was wondering if it is possible to do this and how.
This is a shortened example for simplicity, of the pipeline I'm dealing with:
/**
* prepare tests for parallel
* #param filename Name of the file that contains the testsuites list
*/
def doDynamicParallelSteps(filename){
tests = [:]
echo "doDynamicParallelSteps"
def w = pwd()
def path = "$w/$filename"
// read all the lines into a list, each line is an element in the list
def fh = new File(path)
def lines = fh.readLines()
for (line in lines) {
def values = line.split(":")
def testsuite_name = values[0].trim()
def test_path = values[1].trim()
def test_filename_or_directory = test_path.split("/").getAt(-1);
def is_file = test_filename_or_directory.matches("(.*).php")
def is_custom_mycondition = test_filename_or_directory.matches("MyMatchCondition")
if (is_custom_mycondition){ // large timeout
def time_val = 10
} else { // default timeout
def time_val = 5
}
tests["${test_filename_or_directory}"] = {
stage("UnitTest ${test_filename_or_directory}") {
timeout(time: time_val, unit: 'MINUTES') { // scripted syntax
// other stuff here
} // end timeout
} // end stage
} // end MAP
}
parallel tests
}
If I run this pipeline I got the following output:
hudson.remoting.ProxyException: groovy.lang.MissingPropertyException: No such property: time_val for class: mycustomJob
Then I've tried to set it as global value and it worked but not as expected, because its value doesn't seems to changed, it outputs "5" ignoring my condition.
What am I doing wrong? Can anyone show me the right way or a better approach?
What you are doing looks more pythonic than groovy. You must define the variable 'time_val' on a higher level to make it visible in your scope, like:
def time_val = 5
if (is_custom_mycondition){ // large timeout
time_val = 10
}
Instead of your else part.
You can also define it in a single line, like:
def time_val = is_custom_mycondition ? 10 : 5
Your 'timeout' usage looks correct to me. Just define the variable properly.

How to extract given array of string with numbers from string in groovy

I'm trying to check if commit-msg from git contains particular ticket number with project key of Jira using groovy in Jenkins pipeline
def string_array = ['CO', 'DEVOPSDESK', 'SEC', 'SRE', 'SRE00IN', 'SRE00EU', 'SRE00US', 'REL']
def string_msg = 'CO-10389, CO-10302 new commit'
To extract numbers I am using below logic.
findAll( /\d+/ )*.toInteger()
Not sure how to extract exact ticket number with project key.
Thanks in advance.
You could use Groovy's find operator - =~, combined with a findAll() method to extract all matching elements. For that, you could create a pattern that matches CO-\d+ OR DEOPSDESK-\d+ OR ..., and so on. You could keep project IDs in a list and then dynamically create a regex pattern.
Consider the following example:
def projectKeys = ['CO', 'DEVOPSDESK', 'SEC', 'SRE', 'SRE00IN', 'SRE00EU', 'SRE00US', 'REL']
def commitMessage = 'CO-10389, CO-10302 new commit'
// Generate a pattern "CO-\d+|DEVOPSDEKS-\d+|SEC-\d+|...
def pattern = projectKeys.collect { /${it}-\d+/ }.join("|")
// Uses =~ (find) operator and extracts matching elements
def jiraIds = (commitMessage =~ pattern).findAll()
assert jiraIds == ["CO-10389","CO-10302"]
// Another example
assert ("SEC-1,REL-2001 some text here" =~ pattern).findAll() == ["SEC-1","REL-2001"]
The regex can be assembled a bit simpler:
def projectKeys = ['CO', 'DEVOPSDESK', 'SEC', 'SRE', 'SRE00IN', 'SRE00EU', 'SRE00US', 'REL']
def commitMessage = 'CO-10389, REL-10302 new commit'
String regex = /(${projectKeys.join('|')})-\d+/
assert ['CO-10389', 'REL-10302'] == (commitMessage =~ regex).findAll()*.first()
You can have also another option with finer contol over matching:
def res = []
commitMessage.eachMatch( regex ){ res << it[ 0 ] }
assert ['CO-10389', 'REL-10302'] == res

Optional method arguments

I have two methods that do almost the same thing, but but with a little difference in passing parameters:
def generate_file(filename)
draw
FileUtils.mkdir_p 'tmp/pdf'
#pdf.render_file "#{Rails.root}/tmp/pdf/#{filename}"
end
def generate_pdf(report, version)
draw
path = "tmp/pdf/reports/#{report.reference}"
FileUtils.mkdir_p(path)
#pdf.render_file "#{Rails.root}/#{path}/#{version}"
end
I want to refactor it, and use just the generate_file method when I call a function that generates pdf files. Should I pass an optional params (version = nil) and test if it's defined or not?
Like this:
def generate_file(filname, version = nil, report = nil)
draw
if report && version
path = "tmp/pdf/reports/#{report.reference}"
FileUtils.mkdir_p(path)
#pdf.render_file "#{Rails.root}/#{path}/#{version}"
else
FileUtils.mkdir_p 'tmp/pdf'
#pdf.render_file "#{Rails.root}/tmp/pdf/#{filename}"
end
end
It looks like you have some typos (filname instead of filename) and syntax errors (e.g., if..end..else..end) in the proposed code. How about something more like:
def generate_file(filename, version=nil, report=nil)
draw
report_version = report && version
path = report_version ? "tmp/pdf/reports/#{report.reference}" : "temp/pdf"
FileUtils.mkdir_p( path )
#pdf.render_file "#{ Rails.root }/#{path}/#{ report_version ? version : filename }"
end

Getting a second parameter based on the first parameter in Jenkins

I have a task where my Jenkins job needs two parameters for build. The first specifies the application name and can be either QA, Dev, Prod etc and the second is a server which is dependent on the first one.
Example: If I chose the app name as QA, the second parameter should display values like QAServer1, QAServer2, QAServer3.
I'm using Active Choices Plugin (https://wiki.jenkins.io/display/JENKINS/Active+Choices+Plugin) to get this done but facing an problem in fetching the second parameter contents.
Snapshots:
For obtaining the second parameter, I've written a Groovy code which reads the respective files of the selected first parameter and gets the details.
code:
#!/usr/bin/env groovy
import hudson.model.*
def Appliname = System.getenv("APPNAME")
//println Appliname
def list1 = []
def directoryName = "C:/Users/Dev/Desktop/JSONSTest"
def fileSubStr = Appliname
def filePattern = ~/${fileSubStr}/
def directory = new File(directoryName)
def findFilenameClosure =
{
if (filePattern.matcher(it.name).find())
{
def jsoname = it.name
def jsoname1 = jsoname.reverse().take(9).reverse()
list1.add(jsoname1.substring(1,4))
String listAsString = "[\'${list1.join("', '")}\']"
println "return"+listAsString
}
}
directory.eachFileRecurse(findFilenameClosure)
The above code will print the output as return['QAServer1', 'QAServer2'] which i want to use it as input for the second parameter.
Snapshot of Second parameter:
Somehow the Groovy script is not being executed and second parameter value remains empty. How can i get this done dynamically. Am i following the right away to it. Kindly help me figure out. TIA
Would you like to try below change
From:
def findFilenameClosure =
{
if (filePattern.matcher(it.name).find())
{
def jsoname = it.name
def jsoname1 = jsoname.reverse().take(9).reverse()
list1.add(jsoname1.substring(1,4))
String listAsString = "[\'${list1.join("', '")}\']"
println "return"+listAsString
}
}
directory.eachFileRecurse(findFilenameClosure)
To:
directory.eachFileRecurse {
if (filePattern.matcher(it.name).find()) {
def jsoname = it.name
def jsoname1 = jsoname.reverse().take(9).reverse()
list1.add(jsoname1.substring(1,4))
}
}
return list1

Can groovy string interpolation be nested?

I'm trying to add parameter in Jenkins groovy shell script, then wonder if groovy string interpolation can be used nested way like this.
node{
def A = 'C'
def B = 'D'
def CD = 'Value what I want'
sh "echo ${${A}${B}}"
}
Then what I expected is like this;
'Value what I want'
as if I do;
sh "echo ${CD}"
But it gives some error that $ is not found among steps [...]
Is it not possible?
Like this?
import groovy.text.GStringTemplateEngine
// processes a string in "GString" format against the bindings
def postProcess(str, Map bindings) {
new GStringTemplateEngine().createTemplate(str).make(bindings).toString()
}
node{
def A = 'C'
def B = 'D'
def bindings = [
CD: 'Value what I want'
]
// so this builds the "template" echo ${CD}
def template = "echo \${${"${A}${B}"}}"​
// post-process to get: echo Value what I want
def command = postProcess(template, bindings)
sh command
}
In regard to the accepted answer, if you're putting values in a map anyway then you can just interpolate your [key]:
def A = 'C'
def B = 'D'
def bindings = [ CD: 'Value what I want' ]
bindings["${A}${B}"] == 'Value what I want'
${A}${B} is not a correct groovy syntax.
The interpolation just insert the value of expression between ${}.
Even if you change to the correct syntax and create $ method, the result will not be what you want.
def nested = "${${A}+${B}}"
println nested
static $(Closure closure) { //define $ method
closure.call()
}
CD will be printed.

Resources