Actually a common use case of ours is to have expression inside the when; we have stages which toggle based on an environment variable set on the pipeline job itself, so that we can have a single Jenkinsfile handling both pre- and post-merge workflows.
So for us this wouldn't work, but we can deal with it by having separate Jenkinsfiles and/or using shared libraries instead.
Example pipeline:
ciBuild = env.CI == null ? true : env.CI.toLowerCase() == 'true'
pipeline {
agent none
stages {
stage('Build') {
when { expression { return !ciBuild } }
agent { label 'someLabel' }
steps {
sh "echo Build"
}
}
stage('Test') {
when { expression { return ciBuild } }
agent { label 'someOtherLabel' }
steps {
sh "echo Test"
}
}
}
}
What specifically brought me here is that someOtherLabel points to a huge Docker image which takes a while to spin up; if it's not already cached it can take 20 minutes to pull down. Once I noticed this I got a little scared because our pipelines actually have several more stages, most of which are skipped in the ciBuild scenario. The extra time spent allocating nodes would generate complaints.
Subsequent to commenting I noticed that I can put a when inside a parallel, and if I have {{ agent none }} as above, no node will be allocated. Can you have parallel with a single substage? Even if you have to have a dummy placeholder stage, people might be fine trading the extra logging and UI noise for reduced node allocations.
Hrm, I'll need to look into this - I could have sworn I'd specifically made sure that when is evaluated before the agent is handled.