// BuildFlow buildflow-api CI/CD - clean version // ①拉取代码 -> ②编译打包 -> 推送Harbor -> ③部署 + 飞书通知 def feishuNotify = { String result, String failedStageName = "" -> def dur = currentBuild.durationString.replace(" and counting", "") def commit = "" try { commit = sh(script: "git log -1 --pretty=format:%s", returnStdout: true).trim() } catch(ignored) {} def isOk = (result == "SUCCESS") def color = isOk ? "green" : "red" def statusText = isOk ? "成功" : "失败" def title = "CI/CD " + statusText + " " + env.JOB_NAME + " #" + env.BUILD_NUMBER def fields = [ [is_short: true, text: [tag: "lark_md", content: "**项目**\n" + env.JOB_NAME]], [is_short: true, text: [tag: "lark_md", content: "**耗时**\n" + dur]], [is_short: true, text: [tag: "lark_md", content: "**提交**\n" + commit.take(50)]], [is_short: true, text: [tag: "lark_md", content: "**状态**\n" + statusText]] ] def elements = [[tag: "div", fields: fields], [tag: "hr"]] if (isOk) { elements.add([tag: "div", text: [tag: "lark_md", content: "镜像地址\n`" + env.IMAGE + ":" + env.TAG + "`"]]) } else if (failedStageName) { elements.add([tag: "div", text: [tag: "lark_md", content: "失败阶段\n" + failedStageName]]) } def burl = env.BUILD_URL if (burl == null) { burl = "http://115.191.51.246:8080/job/" + env.JOB_NAME.replace("/", "/job/") + "/" } elements.add([tag: "action", actions: [[tag: "button", text: [tag: "plain_text", content: "查看构建"], url: burl, type: isOk ? "primary" : "danger"]]]) def card = [msg_type: "interactive", card: [header: [title: [tag: "plain_text", content: title], template: color], elements: elements]] def jsonStr = groovy.json.JsonOutput.toJson(card) writeFile file: "/tmp/feishu_msg.json", text: jsonStr sh 'curl -sS -X POST https://open.feishu.cn/open-apis/bot/v2/hook/d215e8ed-edea-4f07-a77c-2a0e5b52d9b9 -H "Content-Type: application/json" -d @/tmp/feishu_msg.json || true' sh 'rm -f /tmp/feishu_msg.json' } pipeline { agent any environment { HARBOR = "43.134.235.58:58080" IMAGE = "${HARBOR}/buildflow/buildflow-api" TAG = "${env.BUILD_NUMBER}" } options { timeout(time: 30, unit: "MINUTES") buildDiscarder(logRotator(numToKeepStr: "10")) } stages { stage("① 拉取代码") { steps { checkout scm sh "git log --oneline -3" } } stage("② 编译打包") { steps { sh "docker build -t ${IMAGE}:${TAG} -t ${IMAGE}:latest ." sh "docker images | grep ${IMAGE} | head -2" } } stage("推送 Harbor") { steps { withCredentials([usernamePassword(credentialsId: "harbor-credentials", usernameVariable: "HUSER", passwordVariable: "HPASS")]) { sh ''' echo $HPASS | docker login $HARBOR -u $HUSER --password-stdin docker push $IMAGE:$TAG docker push $IMAGE:latest docker logout $HARBOR ''' } } } stage("③ 部署") { steps { script { try { node("deploy-agent") { sh ''' docker pull $IMAGE:latest docker rm -f buildflow-api 2>/dev/null || true docker run -d --name buildflow-api --restart unless-stopped -p 5667:5667 $IMAGE:latest ''' } echo "部署完成" } catch (e) { echo "部署节点暂不可用,跳过自动部署。镜像已推送 Harbor。api依赖PG/Mongo/Redis/RabbitMQ" } } } } } post { success { script { feishuNotify("SUCCESS") } } failure { script { feishuNotify("FAILURE", "构建失败,请查看日志") } } always { sh "docker rmi ${IMAGE}:${TAG} ${IMAGE}:latest 2>/dev/null || true" deleteDir() } } }