#!/usr/bin/env groovy /** * 强验证发布 SpringBoot  fat-jar *  - 按端口杀进程 *  - 按 profile 做所有进程级校验 */ def call(Map args = [:]) { String jarName = args.jarName ?: env.JAR_NAME String jarPath = args.jarPath ?: env.JAR_PATH String remoteHost = args.remoteHost ?: env.REMOTE_HOST String remotePort = args.remotePort ?: env.REMOTE_PORT String remotePath = args.remotePath ?: env.REMOTE_PATH String profile = args.profile ?: env.PROFILE String jvmArgs = args.jvmArgs ?: env.JVM_ARGS ?: '' String remoteJar = "${remotePath}/${jarName}" PrintMes("开始发布 ${jarName} [profile=${profile}] 到 ${remoteHost}:${remotePort}", 'yellow') try { /* 1. 按端口杀旧进程,并确认端口已释放 */ sh """ ssh -o StrictHostKeyChecking=no ${remoteHost} ' OLD_PID=\$(lsof -ti:${remotePort} || true) if [ -n "\$OLD_PID" ]; then echo "杀掉占用端口 ${remotePort} 的进程 \$OLD_PID" kill -9 \$OLD_PID sleep 3 fi if lsof -ti:${remotePort}; then echo "端口 ${remotePort} 仍未释放,杀进程失败" exit 1 fi ' """ /* 2. 备份旧包 */ sh """ ssh -o StrictHostKeyChecking=no ${remoteHost} ' test -f ${remoteJar} && mv ${remoteJar} ${remoteJar}-\$(date +%Y%m%d%H%M) || true ' """ /* 3. 传包 + MD5 强校验 */ String localMd5 = sh(script: "md5sum ${jarPath} | awk '{print \$1}'", returnStdout: true).trim() sh "scp -o StrictHostKeyChecking=no ${jarPath} ${remoteHost}:${remoteJar}" // ❌ 修复点:修改 awk 脚本的转义方式,使用单引号包裹,并让 Groovy 正确输出 \$1 String remoteMd5 = sh(script: "ssh -o StrictHostKeyChecking=no ${remoteHost} 'md5sum ${remoteJar} | awk \\'{print \\\$1}\\' '", returnStdout: true).trim() if (localMd5 != remoteMd5) { error("MD5 校验失败:本地 ${localMd5} != 远程 ${remoteMd5}") } /* 4. 启动新进程 */ sh """ ssh -o StrictHostKeyChecking=no ${remoteHost} ' cd ${remotePath} && nohup java ${jvmArgs} -jar ${jarName} --spring.profiles.active=${profile} > server.log 2>&1 & sleep 5 ' """ /* 5. 按 profile 精确校验:有且仅有 1 个进程 */ String procCount = sh( script: "ssh -o StrictHostKeyChecking=no ${remoteHost} 'ps -ef | grep \"java.*${jarName}.*--spring.profiles.active=${profile}\" | grep -v grep | wc -l'", returnStdout: true ).trim() if (procCount != "1") { error("启动校验失败:期望 1 个 ${profile} 进程,实际 ${procCount} 个") } /* 6. 端口已被新进程占用 */ String newPid = sh(script: "ssh -o StrictHostKeyChecking=no ${remoteHost} 'lsof -ti:${remotePort}'", returnStdout: true).trim() if (!newPid) { error("端口 ${remotePort} 未被新进程监听,启动可能失败") } PrintMes("发布成功 ${jarName} [profile=${profile}, pid=${newPid}]", 'green') } catch (Exception e) { PrintMes("发布失败 ${jarName} : ${e.message}", 'red') error('deploySpringBoot failed') } }