When using env object in shared library, env.HOME value doesn't shift with a dockerized stage. When a shell step executes, its HOME points to the correct value.
In the case below, I'd expect env.HOME == sh(script:'echo $HOME', returnStdout: true).trim() and it does on the agent stage but not in the dockerized stage.
This is trivial to work around (use withEnv to set, use ~ or $HOME in shell commands to pull home from shell not groovy layer)
I'd just like to know the why behind it.
/vars/foo.groovy
def info() {
println "Stage: ${env.STAGE_NAME}, env.HOME: ${env.HOME}
sh 'echo HOME=$HOME'
}
# Jenkinsfile
...
stages {
stage('agent') {
steps {
script { foo.info() }
}
}
stage('dockerized') {
agent {
docker {
image runnerImage
reuseNode true
}
}
steps {
script { foo.info() }
}
result
Stage: agent, HOME: /home/ec2-user
echo HOME=/home/ec2-user
HOME=/home/ec2-user
Stage: agent, HOME: /home/ec2-user
echo HOME=/home/jenkins
HOME=/home/jenkins
Silly me, the answer appear during some insomnia. The HOME environment variable was set by the contain's operating system itself and therefore Jenkins and its shared library could not know what it was.
The /etc/passwd and setting of
USERin the image's Dockerfile determines HOME. Any profile or rc files in HOME would add additional env variables.The ways to limit the damage of this class from a library designer point of view are:
sh "ls ${env.HOME}" // bad idea, the HOME may not match container's ideash 'ls $HOME' // better, resolution from shell not Gstringsh "ls ~" // ~ auto resolves to $HOME within shell-e ${HOME}:HOMEI'd also recommend using images what follow suit aligned with the agent OS structure when possible but if your shared library is used by 100s or 1000s of build jobs, you cannot know this will be the case and it is better to reduce the risk.