I'm trying to grok the rules surrounding variables in Groovy/Jenkinsfiles/declarative syntax.
The generic webhook trigger captures HTTP POST content and makes them available as variables available to your Jenkinsfile. E.g.:
pipeline {
agent any
triggers {
GenericTrigger (
genericVariables: [
[ key: "POST_actor_name", value: "\$.actor.name" ]
],
token: "foo"
)
}
stages {
stage( "Set up" ) {
steps {
script {
echo "env var ${env.actor_name}"
echo "global var ${actor_name}"
}
}
}
}
If the HTTP POST content contains a JSON object with an actor_name
field valued "foo", then this prints:
env var foo
global var foo
If the HTTP POST content does not contain the JSON field actor_name
, then this prints
env var null
...then asserts/aborts with a No such property
error.
Jenkins jobs also have a "this project is parameterized" setting, which seems to introduce yet another way to inject variables into your Jenkinsfile. The following Jenkinsfile prints a populated, parameterized build variable, an unpopulated one, and an intentionally nonexistent variable:
pipeline {
agent any
stages {
stage( "Set up" ) {
steps {
script {
echo "1 [${env.populated_var}]"
echo "2 [${env.unpopulated_var}]"
echo "3 [${env.dontexist}]"
echo "4 [${params.populated_var}]"
echo "5 [${params.unpopulated_var}]"
echo "6 [${params.dontexist}]"
echo "7 [${populated_var}]"
echo "8 [${unpopulated_var}]"
echo "9 [${dontexist}]"
}
}
}
}
}
The result is:
1 [foo]
2 []
3 [null]
4 [foo]
5 []
6 [null]
7 [foo]
8 []
...then asserts/aborts with a No such property
error.
The pattern I can ascertain is:
env.
-scoped variables will be NULL if they come from unpopulated HTTP POST content.env.
-scoped variables will be empty strings if they come from unpopulated parameterized build variables.env.
-scoped variables will be NULL if are nonexistent among parameterized build variables.params.
-scoped variables will be NULL if they if are nonexistent among parameterized build variables.params.
-scoped variables will be empty strings if they come from unpopulated parameterized build variables.I have a few questions about this - I believe they are reasonably related, so am including them in this one post:
env.
, params.
, and globally, and what is their relationship (why are they not always 1:1)?Context: in my first Jenkinsfile project, I made use of variables populated by HTTP POST content. Through this, I came to associate a value's absence with the corresponding .env
variable's null-ness. Now, I'm working with variables coming from parameterized build values, and when a value is not populated, the corresponding .env
variable isn't null -- it's an empty string. Therefore, I want to understand the pattern behind when and why these variables are null versus empty, so that I can write solid and simple code to handle absence/non-population of values from both HTTP POST content and parameterized build values.
The answer is a bit complicated.
For 1 and 2:
First of all pipeline, stage, steps... are groovy classes. Everything in there is defined as object/variable.
env is an object that holds pretty much everything,
params holds all parameter ;)
They are both a Map, if you access an empty value it's empty, if you access an non existing one it's null.
The globals are variables itself and if you try to access a non existing the compiler complains.
For 3:
You can define "default" parameter:
pipeline {
agent any
stages {
stage( "Set up" ) {
steps {
script {
params = setConfig(params);
}
}
}
}
}
def merge(Map lhs, Map rhs) {
return rhs.inject(lhs.clone()) { map, entry ->
if (map[entry.key] instanceof Map && entry.value instanceof Map) {
map[entry.key] = merge(map[entry.key], entry.value)
} else {
map[entry.key] = entry.value
}
return map
}
}
def setConfig(givenConfig = [:]) {
def defaultConfig = [
"populated_var": "",
"unpopulated_var": "",
"dontexist": ""
];
effectiveConfig = merge(defaultConfig, givenConfig);
return effectiveConfig
}