Comparing 2 parameters in Jenkins pipeline in a single command - jenkins

what is wrong with below code, comparing 2 strings in groovy
I am trying do the comparison between the 2 parameters in a single line to make it look tidier
if (params.dirname == ((params.path =~ ~/${params.dirname}/).with { matches() ? it[0] : null })) {
print success
}
Throwing Exception -
java.lang.NoSuchMethodError: No such DSL method 'matches' found among steps

There is no need to over-complicate your use case. According to:
params.dirname = hde, params.path = /usr/tmp/jenkins/hde/filename.txt or /usr/hde/jenkins/ing/filename.txt or any random path which has hde in it
you are trying to find if given string a contains substring b. It can be done using Java's method String.contains(String substring). Alternatively you can use regular expression for that, but String.contains() just looks a few times simpler to understand what is your intention. Consider following Groovy script:
def params = [
dirname: 'hde',
path: '/usr/tmp/jenkins/hde/filename.txt'
]
// Using String.contains()
if (params.path.contains(params.dirname)) {
println "Path '${params.path}' contains '${params.dirname}'"
}
// Using regular expression
if (params.path ==~ /(.*)${params.dirname}(.*)/) {
println "Path '${params.path}' contains '${params.dirname}'"
}
When you run it both if statements evaluates to true:
Path '/usr/tmp/jenkins/hde/filename.txt' contains 'hde'
Path '/usr/tmp/jenkins/hde/filename.txt' contains 'hde'

Related

java.lang.IllegalArgumentException: Expected named arguments while executing jobs in parallel

I have a monorepo and i am trying to make them run in parallel
def abc = findJenkinsfileToRun(modifiedFiles)
parallel {
for (file in abc) {
println("Building ${file.toString()}")
load "${file.toString()}/Jenkinsfile"
}
}
This results in the following
java.lang.IllegalArgumentException: Expected named arguments but got org.jenkinsci.plugins.workflow.cps.CpsClosure2#b7ccdc
can anyone help how to resolve this?
You are not using the parallel keyword correctly, it should receive a map of branch names as keys and execution code (closure) as values. See the Documentation.
So in your case you should use something like:
def abc = findJenkinsfileToRun(modifiedFiles)
parallel abc.collectEntries { file ->
["Building ${file.toString()}" : {
// The code to run in parallel
println("Building ${file.toString()}")
load "${file.toString()}/Jenkinsfile"
}]
}

How does this jenkins groovy script work?

This is my groovy Script on Jenkins
def gitURL = "http://bitbucket.webapp.intern.de/scm/myproject.git"
def command = "git ls-remote -h $gitURL"
def proc = command.execute() // line 3
proc.waitFor()
if ( proc.exitValue() != 0 ) {
println "Error, ${proc.err.text}"
System.exit(-1)
}
def branches = proc.in.text.readLines().collect { // line 9
it.replaceAll(/[a-z0-9]*\trefs\/heads\//, '') // line 10
}
return branches
First I do not understand anything. How on line 3 can you call execute on command which is supposed to be a string ??
What type is variable branches in line 9 ???
Is branches a String ??
What is it.replaceAll in line 10 ??? I know replaceAll as method from String. But it has 2 parameters.
I do not see 2 parameters here.
Now I somehow understand branches contains all branches. What I want to do. I only want to have
branches which contain "-REST" it their names. How can I do this ??
My intention was using java. But it does not work.
List<String> branchesNew = new ArrayList<String>();
for(String branch : branchesNew)
{
if(branch.contains("-REST"))
branchesNew.add(branch);
}
line 3: this is a Groovy feature, see http://groovy-lang.org/groovy-dev-kit.html#process-management
line 9: it's a collection (a list, for instance) given as output of the collect method. see also http://groovy-lang.org/groovy-dev-kit.html#_working_with_collections
line 10: the second argument is ''. it replaces the regexp matches (branch prefixes) with an empty string.
You can filter all your wanted branches using the findAll method on collections. Following the given example:
def branchesNew = proc.in.text.readLines().findAll{ it.contains('-REST') }
Look at Filtering and searching for all related manipulation methods.

How to pass variable name, but not its value into /var function as argument piece?

I'm trying to divide a pipeline. Most of the parameters passed successful, but those containing variables are resolved before i need.
Jenkins ver. 2.164.1
Jenkins.file content:
stage ('prebuild') {
steps {
script {
VERSION="temprorary-value"
POSTBUILDACTION="make.exe \\some\\path\\file_${VERSION}"
}
}
}
stage ('build') {
steps {
script {
build (POSTBUILDACTION)
}
}
}
build.groovy content:
def call (String POSTBUILDACTION) {
...
checkout somefile
VERSION=readFile(somefile)
bat "${POSTBUILDACTION}"
}
here i expected that version will be taken from redefined VERSION variable but POSTBUILDACTION passed into the function as a string. In result it's called as is ("make.exe \some\path\file_temprorary-value"). In fact command i'd like to get is (somefile contains only one number, for example "5")
make.exe \some\path\file_5
But now i have
make.exe \some\path\file_temprorary-value
Or if i trying to pass \${VERSION} like:
POSTBUILDACTION="make.exe \\some\\path\\file_\${VERSION}"
- it's transfer as is:
make.exe \some\path\file_${VERSION}
I've tried to view a class of POSTBUILDACTION in prebuild stage - it's equal "class org.codehaus.groovy.runtime.GStringImpl" and same on build stage after passing throw - it become a string: "class java.lang.String"
So how to pass into a function argument contained a variable, but not it's value ?
OR
to "breathe life" into a dry string like
'make.exe \\some\\path\\file_${VERSION}'
so the variables could be resolved?
Option 1 - lazy evaluation (#NonCPS)
You can use a GString with lazy evaluation, but since Jenkins doesn't serialize lazy GStrings you'll have to return it from a #NonCPS method like so:
#NonCPS
def getPostBuildAction() {
"make.exe \\some\\path\\file_${ -> VERSION }"
}
stage ('prebuild') {
...
}
Then you set POSTBUILDACTION=getPostBuildAction() and you can use POSTBUILDACTION as you wanted, but be aware that the object you have here is a groovy.lang.GString and not a String, so you'll want to change your parameter class (or simply use def.)
Option 2 - use a closure for every call
You can use an eager GString inside a closure:
def String getPostBuildAction() {
"make.exe \\some\\path\\file_$VERSION"
}
But here you'll have to call getPostBuildAction() every time you want a different reading of VERSION, so you'll have to replace POSTBUILDACTION with this closure.

Jenkins Pipeline define and set variables

I am using branch name to pass it into build script. $(env.BRANCH_NAME).
I would like to manipulate the value before using it. For example in case we build from trunk I want suffix for the build output be empty but in case of branch I want it to be -branch name.
currently I am doing it by defining environment section.
environment {
OUTPUT_NAME_SUFFIX = ($(env.BRANCH_NAME) == 'trunk') ? '': $(env.BRANCH_NAME)
}
I am getting this error:
WorkflowScript: 4: Environment variable values must either be single quoted, double quoted, or function calls. # line 4, column 62.
(env.BRANCH_NAME) == 'trunk') ? '': $(en
^
What the best way to define variables and eval their values in scope of pipeline.
TIA
You can use string interpolation to evaluate the expression:
environment {
OUTPUT_NAME_SUFFIX = "${env.BRANCH_NAME == 'trunk' ? '': env.BRANCH_NAME}"
}
This will fix the error you're getting, however pipeline does not allow you to have environment variables that are of 0 length, aka empty string (JENKINS-43632).
That means that setting OUTPUT_NAME_SUFFIX to '' is like unseting it. You might want to precalculate the whole name of your output, so that your env variable is never an empty string.
I have solved it by adding following code. So far had no issues with empty strings.
stage('Set Environmnet'){
steps {
script {
if(BRANCH_NAME == 'trunk'){
env.OUTPUT_NAME_SUFFIX = ''
}else if (BRANCH_NAME.startsWith("branches")){
env.OUTPUT_NAME_SUFFIX = "-" + BRANCH_NAME.substring(BRANCH_NAME.lastIndexOf("/")+1)
}else{
env.OUTPUT_NAME_SUFFIX = ''
}
}
}
}

How to print each element of Multi-line String Parameter?

I've Pipeline job in Jenkins (v2.7.1) where I'd like to print each element of Multi-line String parameter (Params) with 3 strings in each line: Foo, Bar, Baz as an input.
So I've tried the following syntax (using split and each):
Params.split("\\r?\\n").each { param ->
println "Param: ${param}"
}
but it fails with:
java.lang.UnsupportedOperationException: Calling public static java.lang.Object
org.codehaus.groovy.runtime.DefaultGroovyMethods.each(java.lang.Object,groovy.lang.Closure) on a CPS-transformed closure is not yet supported (JENKINS-26481); encapsulate in a #NonCPS method, or use Java-style loops
at org.jenkinsci.plugins.workflow.cps.GroovyClassLoaderWhitelist.checkJenkins26481(GroovyClassLoaderWhitelist.java:90)
which suggest to encapsulate in a #NonCPS method, or use Java-style loops.
So I've tried to encapsulate in a #NonCPS method like:
#NonCPS
def printParams() {
Params.split("\\r?\\n").each { param ->
println "Param: ${param}"
}
}
printParams()
but it fails with:
org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use staticMethod org.codehaus.groovy.runtime.DefaultGroovyMethods println groovy.lang.Closure java.lang.Object
Without the function (as per first example), adding #NonCPS at the beginning it complains about unexpected token.
I also tried Java-style syntax as suggested by using for operator (similar as here):
String[] params = Params.split("\\r?\\n")
for (String param: params) {
println "Param: ${param}"
}
which seems to work in plain Groovy, but it fails in Jenkins with:
java.io.NotSerializableException: java.util.AbstractList$Itr
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:860)
Which syntax I should use to make it work?
The code works fine when disabling a Use Groovy Sandbox option and adding #NonCPS helper method. Alternatively, as suggested by #agg3l, proceed to Jenkins management to permit this method access.
So the working code is (same as the 2nd example):
#NonCPS
def printParams() {
Params.split("\\r?\\n").each { param ->
println "Param: ${param}"
}
}
printParams()
I know it's an old post but this is my way to do it, hopefully help anyone else
params.readLines().each {
println it
if (it) {
// if you want to avoid make operation with empty lines
}
}

Resources