Top-level vs stage-level environment for DEPLOY_TARGET consistency in steps and post
0 reputation · 27 Aug 2024, 20:10 UTC
0 reputation · 27 Aug 2024, 20:10 UTC
A declarative pipeline needs a single value for DEPLOY_TARGET that is used in stage steps, failure handling, and archiving. The documented approaches are a top-level environment block that provides a pipeline-wide default and a stage-level environment block that is scoped to that stage.
The concrete constraint is consistent resolution of the same key across steps and the stage post block. Declarative Pipeline environment scoping is implemented by Pipeline plugins rather than Jenkins core alone, so precedence and visibility can be version sensitive.
The unresolved behavior concerns precedence and timing for post actions. It is unclear whether a stage post block observes the stage-level override, falls back to the top-level value, or uses a value captured earlier in the stage execution. This matters when cleanup, notifications, or artifact handling depend on DEPLOY_TARGET.
Does a stage post block resolve environment variables from the stage scope or from the pipeline scope? Is the precedence of a stage-level entry over a top-level entry stable across Declarative Pipeline plugin versions? Should DEPLOY_TARGET be defined explicitly at stage level to guarantee consistent use in steps and post actions?
35275 reputation · 28 Aug 2024, 06:59 UTC
A stage post block resolves environment variables from the stage scope. If the stage defines its own environment entry for DEPLOY_TARGET, both the stage's steps and its post actions see that value. If the stage has no override, both fall back to the top-level value. So within a single stage, steps and post are consistent — you do not get a mix of the two scopes.
Confirmed by long-standing Declarative Pipeline behavior:
environment block is a pipeline-wide default.environment block shadows the top-level entry of the same name for everything inside that stage, including post conditions (always, failure, success).post action reads the variable at the moment it executes.The part that is version-sensitive and should be verified on your installation: this scoping is implemented by the Pipeline Model Definition plugin (with workflow-cps / workflow-basic-steps), not Jenkins core. Edge cases — especially around parallel and matrix stages — have had bug fixes across plugin releases, so an older LTS plugin set may not match current documentation.
Yes — define DEPLOY_TARGET explicitly at stage level in any stage whose cleanup, notification, or archiving logic depends on it:
pipeline {
agent any
environment {
DEPLOY_TARGET = 'staging' // pipeline-wide default
}
stages {
stage('Deploy Prod') {
environment {
DEPLOY_TARGET = 'prod' // shadows the default for this stage
}
steps {
sh 'echo deploying to $DEPLOY_TARGET'
}
post {
failure {
sh 'echo rollback for $DEPLOY_TARGET'
}
always {
archiveArtifacts artifacts: "reports/${env.DEPLOY_TARGET}/**", allowEmptyArchive: true
}
}
}
}
}This keeps the override declarative and local. Steps and post in that stage both see prod; every other stage sees staging.
Avoid env.DEPLOY_TARGET = 'x' inside steps. That mutates the run's environment globally and can leak into later stages' post blocks, which is exactly the inconsistency you are trying to prevent. Declarative environment blocks are scoped; imperative assignment is not.
Because behavior is plugin-version dependent, run a minimal test:
DEPLOY_TARGET = 'a' and one stage with environment { DEPLOY_TARGET = 'b' } whose steps and post { always { echo env.DEPLOY_TARGET } } both echo the value. Both should print b.post should both print a.If your test shows the post block printing the top-level value while steps print the override, report the plugin versions — that would indicate a version-specific bug rather than intended behavior.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.