I have a Jenkinsfile with some properties, for example
trace = false
userNotifications = [
build_master : [name : 'name',
email : 'email',
slackid: 'slack id',
slackchannel: 'slack channel']
]
env.aProperty = "aValue"
node('COMPILE')
{
...
}
I want to parse the above Jenkinsfile inside groovy code in order to access some of the property values.
When I use GroovyShell like this
Binding binding = new Binding()
GroovyShell shell = new GroovyShell(binding)
Object groovyDsl = shell.evaluate(clean)
I get this error
groovy.lang.MissingMethodException: No signature of method: Script1.node() is applicable for argument types: (String, Script1$_run_closure1) values: [COMPILE, Script1$_run_closure1@7d804e7]
I might be able to get around the particular error with some Groovy meta-programming, however, I am unsure if this is the right direction. My question is what is the best way to parse a Jenkinsfile in Groovy code? This is Groovy DSL at the end of the day and I would expect it to be more straightforward.
Here is how I eventually did what I wanted:
import org.codehaus.groovy.control.CompilerConfiguration
class JenkinsfileParser {
static void main(String[] args) {
LinkedHashMap vars = JenkinsfileParser.parse('Jenkinsfile' as File)
println vars.toString()
}
static LinkedHashMap parse(File jenkinsfile) {
CompilerConfiguration config = new CompilerConfiguration()
config.scriptBaseClass = JenkinsfileBaseClass.class.name
Binding binding = new Binding()
GroovyShell shell = new GroovyShell(this.class.classLoader, binding, config)
String clean = jenkinsfile.text.replace('import hudson.model.*', '')
.replace('import hudson.EnvVars', '')
Script script = shell.parse(clean)
script.run()
return binding.variables
}
static abstract class JenkinsfileBaseClass extends Script {
LinkedHashMap<String, Closure> nodeClosures = new LinkedHashMap<>()
LinkedHashMap env = new LinkedHashMap()
CurrentBuild currentBuild = new CurrentBuild()
LinkedHashMap parallelClosures = new LinkedHashMap<>()
void node(String name, Closure closure) {
nodeClosures.put(name, closure)
}
void parallel(LinkedHashMap closures) {
parallelClosures.putAll(closures)
}
class CurrentBuild {
List<String> expectedResults = new ArrayList<>()
boolean resultIsBetterOrEqualTo(String expected) {
expectedResults << expected
return true
}
}
}
}
The JenkinsfileBaseClass
is specific to my Jenkinsfile and would need adaptation for a different Jenkinsfile.
Relevant documentation can be found here: https://groovy-lang.org/integrating.html
I tried using the implementation group: 'org.jenkins-ci.main', name: 'jenkins-core', version: '2.9'
package from the maven repository http://repo.jenkins-ci.org/public/
, however, there doesn't seem to be anything in there useful for my case.
Let me know if there's a better or more elegant way of doing it.