Jenkins脚本式Pipeline生产部署阶段npm命令报ENOENT错误
问题根因
当前生产部署阶段失败是多个逻辑问题叠加导致的:
- 直接触发报错的原因:前序
Deploy Development阶段执行末尾调用了deleteDir()清空了整个Jenkins工作目录,把之前拉取的项目源码、package.json等文件全部删除了。进入生产部署阶段时工作区是空的,执行npm run build-prod-ci时找不到同路径下的package.json,直接抛出ENOENT文件不存在错误。 - 隐藏bug1:生产阶段的
finally块执行顺序写反,先执行deleteDir()删目录再执行cf logout,如果后续cf操作依赖工作区内的配置文件,会直接触发命令执行失败。 - 隐藏bug2:
cf login命令用单引号包裹,Jenkins流水线中单引号包裹的shell脚本不会替换Groovy注入的凭证变量,就算npm构建步骤通过,后续cf登录会因为拿不到正确的账号密码报认证错误。
修复方案
- 调整工作区清理逻辑:不要在中间部署阶段执行
deleteDir()清空工作区,将全量目录清理、账号登出这类收尾操作统一放到整个Pipeline的post块中,等所有阶段执行完成后再运行,避免中间阶段删文件影响后续流程。如果暂时不想调整前序阶段的逻辑,就在生产部署阶段最开头重新拉取代码:checkout scm。 - 调整生产阶段内部逻辑顺序:将cf登出操作放到部署操作完成后立即执行,不要放在删除目录的步骤之后。
- 修正shell命令的引号:将
cf login行的单引号改为双引号,保证凭证变量可以被正常解析替换。
修复后参考代码
生产阶段修复片段
stage('Deploy Production') { echo "Deploy Prod on: ${env.BRANCH_NAME}" // 如果前序阶段已经删了工作区,先重新拉取源码 checkout scm try { if (env.BRANCH_NAME == 'master'){ withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'XX', usernameVariable: 'XXXXX', passwordVariable: 'XXXXXX']]) { sh 'npm run build-prod-ci' // 替换为双引号,保证凭证变量正常解析 sh "cf login -u ${XXXXX} -p ${XXXXXX} -a website.com -o XXX -s XXXX" sh 'cf blue-green-deploy Dashboard' sh 'cf delete Dashboard-old -f' sh 'cf logout' } } } finally { // 所有操作完成后再清理工作区 deleteDir() } }
更优的全局清理逻辑(推荐)
把清理逻辑从各个阶段抽到最外层post块,从根源避免中间阶段误删文件:
pipeline { agent any stages { // 此处放原有所有阶段:代码拉取、测试构建、开发部署、生产部署 // 所有阶段内部不要写deleteDir、cf logout这类全局收尾逻辑 } post { always { // 无论流水线成功失败,最后统一执行收尾 sh 'cf logout' deleteDir() } } }
内容的提问来源于stack exchange,提问作者QQP
相关产品推荐
相关产品推荐

