1

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?

gek
  • 524
  • 6
  • 18

1 Answers1

0

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.

towel
  • 2,094
  • 1
  • 20
  • 30