environment sets variables for the pipeline or one stage: literals, Groovy expressions, or a step's output. Steps see them as environment variables, and Groovy can read them too:
pipeline {
agent { label 'linux' }
environment {
APP_NAME = 'booknest'
IMAGE_TAG = "${env.BRANCH_NAME ?: 'main'}-${env.BUILD_NUMBER}"
KERNEL = sh(script: 'uname -r', returnStdout: true).trim()
}
stages {
stage('Test') {
environment { PGDATABASE = 'booknest_test' }
steps {
echo "Groovy sees IMAGE_TAG=${IMAGE_TAG}"
sh 'echo "shell: $APP_NAME:$IMAGE_TAG on $KERNEL, PGDATABASE=$PGDATABASE"'
}
}
stage('Package') {
steps {
sh 'echo "PGDATABASE=${PGDATABASE:-unset}"'
withEnv(['NODE_ENV=production']) { sh 'echo "NODE_ENV=$NODE_ENV"' }
}
}
}
}The lines the steps printed:
Groovy sees IMAGE_TAG=main-1 shell: booknest:main-1 on 6.18.33.2-microsoft-standard-WSL2, PGDATABASE=booknest_test PGDATABASE=unset NODE_ENV=production
KERNEL ran uname -r on the agent before the first stage; PGDATABASE existed only in its stage; withEnv scopes a variable to a block. Jenkins 8,793 adds BUILD_NUMBER, JOB_NAME, WORKSPACE, NODE_NAME, BUILD_URL, and in multibranch jobs BRANCH_NAME and CHANGE_ID, hence the main fallback in IMAGE_TAG. Mind the quotes: in sh '...$APP_NAME' the shell expands the variable on the agent; in sh "...${APP_NAME}" Groovy substitutes it before the shell runs. The results match here, but only single quotes are safe for secrets.