Jenkins:当流水线被Milestone中止时将构建状态改为SUCCESS
解决Jenkins构建因Milestone标记为NOT_BUILT的问题
我完全理解你的痛点:那些停在INT阶段的构建明明测试全过、部署成功,却因为后续执行的milestone()被标记为灰色(NOT_BUILT),确实会让团队成员困惑。下面是针对你的场景的具体解决方案:
核心思路
问题的根源在于milestone()的默认行为:当新构建到达某个里程碑时,所有未到达该里程碑的未完成旧构建会被自动中止并标记为NOT_BUILT。你的流水线中milestone()放在PRE审批之后,导致停留在审批阶段的构建(未到达该里程碑)会被后续构建影响。
我们可以通过两个关键调整解决这个问题:
- 将里程碑前置到INT部署完成后,确保所有完成INT部署的构建都通过第一个里程碑,后续构建不会影响它们的状态。
- 在审批被中止/超时时,主动将构建状态设置为SUCCESS并结束流水线,避免构建处于“未完成”状态。
具体代码修改
1. 调整里程碑位置(INT部署后)
首先,在完成INT部署后添加第一个里程碑,确保所有成功部署到INT的构建都标记为“已通过该阶段”:
stage('Deploy to INT') { steps { echo 'Executing INT deployment...' // 这里是你的INT部署逻辑 } post { success { // 只有INT部署成功才标记里程碑 milestone(label: 'INT Deployment Completed') } } }
2. 修改PRE审批阶段代码
在审批被中止或超时时,主动设置构建状态为SUCCESS,并结束流水线:
/************** PRE **************/ stage('Approval for PRE') { def approvalGranted = false try { timeout(time: approvalTime, unit: approvalTimeUnit) { input message: 'Do you approve the deployment to PRE?', ok: 'Approve' approvalGranted = true } } catch (Exception ex) { echo "PRE approval skipped: ${ex.getMessage()}" // 标记构建为SUCCESS,因为INT部署已完成且测试通过 currentBuild.result = 'SUCCESS' // 自定义构建名称,方便团队识别是仅INT部署的构建 currentBuild.displayName = "${currentBuild.displayName} (INT Only)" return } if (!approvalGranted) { currentBuild.result = 'SUCCESS' currentBuild.displayName = "${currentBuild.displayName} (INT Only)" return } } // 仅审批通过才执行后续PRE部署步骤 if (approvalGranted) { stage('Deploy to PRE') { steps { echo 'Executing PRE deployment...' // 你的PRE部署逻辑 } post { success { milestone(label: 'PRE Deployment Completed') } } } }
3. PROD审批阶段同理
PROD审批和部署可以复用同样的逻辑,确保未通过审批的构建也保持SUCCESS状态:
stage('Approval for PROD') { def approvalGranted = false try { timeout(time: approvalTime, unit: approvalTimeUnit) { input message: 'Do you approve the deployment to PROD?', ok: 'Approve' approvalGranted = true } } catch (Exception ex) { echo "PROD approval skipped: ${ex.getMessage()}" currentBuild.result = 'SUCCESS' currentBuild.displayName = "${currentBuild.displayName} (PRE Only)" return } if (!approvalGranted) { currentBuild.result = 'SUCCESS' currentBuild.displayName = "${currentBuild.displayName} (PRE Only)" return } } if (approvalGranted) { stage('Deploy to PROD') { steps { echo 'Executing PROD deployment...' // 你的PROD部署逻辑 } post { success { milestone(label: 'PROD Deployment Completed') } } } }
为什么这个方案有效?
- 里程碑前置:完成INT部署的构建会通过第一个里程碑,后续构建执行到该里程碑时,只会中止正在执行INT部署的未完成构建,不会影响已经完成INT部署的构建。
- 主动设置状态:审批被中止时,我们手动将构建状态设为SUCCESS并结束流水线,避免构建处于“未完成”状态,彻底杜绝后续里程碑修改其状态的可能。
- 自定义构建名称:通过
displayName标记仅部署到INT/PRE的构建,让团队一眼就能识别构建的范围,减少困惑。
内容的提问来源于stack exchange,提问作者Patrick T
相关产品推荐
相关产品推荐

