I recently ran into something of a puzzler while working on some Jenkins builds with a coworker. He's been using params.VARIABLE
and env.VARIABLE
interchangably and having no issues with it. Meanwhile, I started getting null object errors on one of his calls to a parameter object through the environment on this line of code:
if(!deploy_environments.contains(env.ENVIRONMENT_NAME.trim()) || params.INVOKE_PARAMETERS ) {
ENVIRONMENT_NAME
here is a parameter. I started getting this error:
java.lang.NullPointerException: Cannot invoke method trim() on null object
This build is executing as a child of another build. The ENVIRONMENT_NAME
parameter is passed down to the child from that parent build.
He was not seeing this error at all on a different Jenkins master. When I changed the reference above from env.ENVIRONMENT_NAME
to params.ENVIRONMENT_NAME
the issue went away.
I could find no reference to params == env
in the Jenkins documentation, so I created a build to try to clarify their relationship.
pipeline {
agent {
label 'jenkins-ecs-slave'
}
environment {
ENV_VARIABLE = 'Environment'
}
parameters {
string(description: 'Parameter', name: 'PARAMETER_VARIABLE', defaultValue: 'Parameter')
}
stages {
stage('Output Parameters'){
steps {
script {
echo "Environment: ${env.ENV_VARIABLE}"
echo "Parameter: ${params.PARAMETER_VARIABLE}"
echo "Environment from params: ${params.ENV_VARIABLE}"
echo "Parameter from Env: ${env.PARAMETER_VARIABLE}"
echo "Inspecific reference ENV_VARIABLE: $ENV_VARIABLE"
echo "Inspecific reference PARAMETER_VARIABLE: $PARAMETER_VARIABLE"
sh 'echo "Shell environment: $ENV_VARIABLE"'
sh 'echo "Shell parameter: $PARAMETER_VARIABLE"'
}
}
}
}
}
The first time I ran this on my Jenkins master, it only included the first four lines (echo env.ENV
, echo param.PARAM
, echo env.PARAM
, echo param.ENV
) it succeeded with the following output:
[Pipeline] {
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Output Parameters)
[Pipeline] script
[Pipeline] {
[Pipeline] echo
Environment: Environment
[Pipeline] echo
Parameter: Parameter
[Pipeline] echo
Environment from params: null
[Pipeline] echo
Parameter from Env: null
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
And I thought, "Aha!" Problem solved. They're not the same.
However, that box promptly froze up on me afterwards and refused to queue anymore builds. I haven't finished debugging it, but it's not out of line to wonder if that master is just messed up.
So I went and ran it on a third Jenkins master we have hanging around. It's at this point I added the additional lines you see in the script above to further clarify. The first time I ran this script on that box, it failed on the "Inspecific reference to $PARAMETER_VARIABLE line" with the following output:
[Pipeline] {
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Output Parameters)
[Pipeline] script
[Pipeline] {
[Pipeline] echo
Environment: Environment
[Pipeline] echo
Parameter: Parameter
[Pipeline] echo
Environment from params: null
[Pipeline] echo
Parameter from Env: null
[Pipeline] echo
Inspecific reference ENV_VARIABLE: Environment
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
groovy.lang.MissingPropertyException: No such property: PARAMETER_VARIABLE for class: groovy.lang.Binding
Okay, so far so good. This makes sense. They aren't the same. You can reference Environment variables in echos and shells with out specifically referencing the environment object, but can't do the same with parameters. Consistent, reasonable, I'm good with this.
So then I removed the two lines doing the "inspecific reference" and the script succeeded with the following output:
[Pipeline] {
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Output Parameters)
[Pipeline] script
[Pipeline] {
[Pipeline] echo
Environment: Environment
[Pipeline] echo
Parameter: Parameter
[Pipeline] echo
Environment from params: null
[Pipeline] echo
Parameter from Env: Parameter
[Pipeline] sh
[Environment Testing] Running shell script
+ echo 'Shell environment: Environment'
Shell environment: Environment
[Pipeline] sh
[Environment Testing] Running shell script
+ echo 'Shell parameter: Parameter'
Shell parameter: Parameter
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
And now I'm completely confuddled. What the hell? I ran it a couple of times just to be sure, and got the same successful output as above, consistently.
Granted, none of the previous builds that showed env.PARAM
as null
had really succeeded in a clean environment (the one that succeeded was in an environment the promptly imploded on me afterwards). So maybe if there's an error in the Jenkins pipeline, it short circuits the loading of parameters into the environment or something? I tried adding echo "$I_SHOULD_FAIL"
to the script to force an error in an attempt to reproduce what was I seeing. No dice:
[Pipeline] {
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Output Parameters)
[Pipeline] script
[Pipeline] {
[Pipeline] echo
Environment: Environment
[Pipeline] echo
Parameter: Parameter
[Pipeline] echo
Environment from params: null
[Pipeline] echo
Parameter from Env: Parameter
[Pipeline] sh
[Environment Testing] Running shell script
+ echo 'Shell environment: Environment'
Shell environment: Environment
[Pipeline] sh
[Environment Testing] Running shell script
+ echo 'Shell parameter: Parameter'
Shell parameter: Parameter
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
groovy.lang.MissingPropertyException: No such property: I_SHOULD_FAIL for class: groovy.lang.Binding
So what's going on here? What's the relationship between environment
and parameters
in Jenkins pipelines? What is that relationship supposed to be and why does it seem to be inconsistent?
The parameters are available as environment variables. So e.g. a shell ($FOO, %FOO%) or Ant ( ${env. FOO} ) can access these values.
A build parameter allows us to pass data into our Jenkins jobs. Using build parameters, we can pass any data we want: git branch name, secret credentials, hostnames and ports, and so on. Any Jenkins job or pipeline can be parameterized.
What are Environment Variables in Jenkins? Environment variables are global key-value pairs Jenkins can access and inject into a project. Use Jenkins environment variables to avoid having to code the same values for each project. Other benefits of using Jenkins environment variables include improved security.
Basically this works as follows
env
contains all environment variables.params
contains all build parameters.Environment variables can be overridden or unset, but params
is an immutable Map and cannot be changed. Best practice is to always use params
when you need to get a build parameter.
See Global Variable Reference for more details regarding the variables.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With