stages.k8s.groovy 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. // can be called locally, without "def"
  2. myUtil = { ->
  3. println "hello myUtil"
  4. }
  5. sharedLibsPath = "${env.WORKSPACE}/sharedLibs"
  6. backup_destination = '/var/jenkins_home/backups'
  7. backup_targetFile = 'javaDockerImage.tar'
  8. BACKUP_MAX = 3
  9. // 获取镜像URL
  10. generateFullImageUri = {Map DOCKER, String base_branch, String BUILD_NUMBER ->
  11. return "${DOCKER.registry}/${DOCKER.image}:${base_branch}-${BUILD_NUMBER}"
  12. }
  13. // 获取镜像名
  14. generateImageName = {Map DOCKER, String base_branch, String BUILD_NUMBER ->
  15. return "${DOCKER.image}:${base_branch}-${BUILD_NUMBER}"
  16. }
  17. def processString(String content) {
  18. return content
  19. }
  20. def buildJar(Object SERVICE, String path='projdir') {
  21. echo "-----> Building project package ..."
  22. dir(path) {
  23. if (SERVICE.module != null && SERVICE.module.trim())
  24. sh "$MAVEN_HOME/bin/mvn clean package -pl \"${SERVICE.module}\" -am -Dmaven.test.skip=true"
  25. else
  26. sh "$MAVEN_HOME/bin/mvn clean package -Dmaven.test.skip=true"
  27. }
  28. return path
  29. }
  30. @Deprecated
  31. def backup_jar(Object SERVICE, String srcPath, String workingPath='projdir') {
  32. echo "-----> Backup project artifact ..."
  33. def module = SERVICE.module == null ? '' : (SERVICE.module[-1] == '/' ? SERVICE.module : SERVICE.module + '/')
  34. path = "${backup_destination}/${JOB_NAME}/${BUILD_NUMBER}/target"
  35. sh """if [ -d ${path} ];
  36. then
  37. echo \"${path} already exists\"
  38. else
  39. mkdir -p ${path}
  40. fi
  41. cp ${workingPath}/${module}${srcPath} ${path}
  42. """
  43. }
  44. def cleanDockerImage(String dockerImgName) {
  45. sh "docker rmi ${dockerImgName}"
  46. }
  47. def backupDockerImage(String dockerImgName) {
  48. echo "-----> Backup artifact(docker image : ${dockerImgName}) ..."
  49. path = "${backup_destination}/${JOB_NAME}/${BUILD_NUMBER}"
  50. // docker save ${dockerImgName} | gzip > ${backup_targetFile}.tar.gz
  51. sh """
  52. docker save ${dockerImgName} -o ${backup_targetFile}
  53. if [ -d ${path} ];
  54. then
  55. echo \"${path} already exists\"
  56. else
  57. mkdir -p ${path}
  58. mv ${backup_targetFile} ${path}
  59. fi
  60. """
  61. }
  62. def backupK8sConfigs(String[] files2backup) {
  63. path = "${backup_destination}/${JOB_NAME}/${BUILD_NUMBER}/k8s"
  64. sh """if [ -d ${path} ];
  65. then
  66. echo \"${path} already exists!\"
  67. else
  68. mkdir -p ${path}
  69. fi
  70. """
  71. for(file in files2backup) {
  72. sh "cp -r ${file} ${path}"
  73. }
  74. }
  75. def cleanJar(String path='projdir') {
  76. echo "-----> Cleaning project package ..."
  77. dir(path){
  78. sh '$MAVEN_HOME/bin/mvn clean'
  79. }
  80. return path
  81. }
  82. def generateDockerfile(Object SERVICE, String pathOfDockerfile='projdir') {
  83. def module = SERVICE.module == null ? '' : (SERVICE.module[-1] == '/' ? SERVICE.module : SERVICE.module + '/')
  84. echo "-----> Generating Dockerfile: ${pathOfDockerfile}/Dockerfile ..."
  85. sh """cat > ${pathOfDockerfile}/Dockerfile<<EOF
  86. FROM openjdk:17-alpine as final
  87. ADD ${module}target/${SERVICE.jar} /app/target/${SERVICE.jar}
  88. EOF
  89. """
  90. return pathOfDockerfile
  91. }
  92. def buildDockerImage(Object SERVICE, Object DOCKER, String base_branch, projDir='projdir', String filter2Remove=null) {
  93. def imageUri = generateFullImageUri(DOCKER, base_branch, BUILD_NUMBER)
  94. echo "-----> Building docker image: ${imageUri} ..."
  95. dir(projDir) {
  96. docker.withRegistry("http://${DOCKER.registry}", "${DOCKER.push_credentialId}") {
  97. def imageName = generateImageName(DOCKER, base_branch, BUILD_NUMBER)
  98. def image = docker.build(imageName)
  99. image.push()
  100. sh "docker rmi ${imageName}"
  101. // sh "docker rmi ${imageUri}"
  102. if(filter2Remove != null)
  103. sh "docker image prune --filter label=${filter2Remove} -f"
  104. }
  105. }
  106. return imageUri
  107. }
  108. def restoreDockerImage(Object DOCKER, String workspace, String base_branch, String rollbackBuildNumber) {
  109. dir(workspace) {
  110. imageUri = generateFullImageUri(DOCKER, base_branch, rollbackBuildNumber)
  111. // gunzip ${backup_targetFile}.tar.gz | docker load
  112. sh "docker load -i ${backup_targetFile}"
  113. // in case, docker image doesn't exist in remote registry
  114. docker.withRegistry("http://${DOCKER.registry}", "${DOCKER.push_credentialId}") {
  115. def image = docker.image(imageUri)
  116. image.push()
  117. }
  118. }
  119. return imageUri
  120. }
  121. def deployWithConfigmapEnvOnly(SERVICE, K3S, String base_branch, String[] args, configmapEnv="./configmap-env.ini", namespace='ahxpm') {
  122. print "loading ${sharedLibsPath}/k3sUtil.groovy..."
  123. def k3sUtils = load "${sharedLibsPath}/k3sUtil.groovy"
  124. def configmap_env_name = k3sUtils.applyConfigMapEnv(SERVICE, K3S, configmapEnv, namespace)
  125. def java_args = '['
  126. args.each{item -> java_args += "\"$item\","}
  127. java_args = java_args[0..-2] + ']'
  128. kvs = [:]
  129. kvs.put('<service_name>', SERVICE.name)
  130. kvs.put('<service_version>', SERVICE.version)
  131. kvs.put('<release>', base_branch)
  132. kvs.put('<COMMIT_SHA>', COMMIT_SHA)
  133. kvs.put('<imagePullSecret>', K3S.pull_secretId)
  134. kvs.put('<docker_image>', imageUri)
  135. kvs.put('<java_args>', java_args)
  136. if (SERVICE.health != null)
  137. kvs.put('<service_health>', SERVICE.health)
  138. kvs.put('<configmap_env_name>', configmap_env_name)
  139. k3sUtils.generateDeployment(kvs, 'deployment.yaml')
  140. k3sUtils.applyDeployment(K3S, 'deployment.yaml')
  141. k3sUtils.generateService(kvs, 'service.yaml')
  142. k3sUtils.applyService(K3S, 'service.yaml')
  143. }
  144. def deployWithConfigmapEnvOnly_rollback(SERVICE, K3S, String rollbackBuildNumber, String[] args, configmapEnv="./configmap-env.ini", namespace='ahxpm') {
  145. print "loading ${sharedLibsPath}/k3sUtil.groovy..."
  146. def k3sUtils = load "${sharedLibsPath}/k3sUtil.groovy"
  147. dir("${backup_destination}/${JOB_NAME}/${rollbackBuildNumber}/k8s") {
  148. def configmap_env_name = k3sUtils.applyConfigMapEnv(SERVICE, K3S, configmapEnv, namespace)
  149. def java_args = '['
  150. args.each{item -> java_args += "\"$item\","}
  151. java_args = java_args[0..-2] + ']'
  152. kvs = [:]
  153. kvs.put('<service_name>', SERVICE.name)
  154. kvs.put('<service_version>', SERVICE.version)
  155. kvs.put('<release>', BASE_BRANCH)
  156. kvs.put('<COMMIT_SHA>', COMMIT_SHA)
  157. kvs.put('<imagePullSecret>', K3S.pull_secretId)
  158. kvs.put('<docker_image>', imageUri)
  159. kvs.put('<java_args>', java_args)
  160. if (SERVICE.health != null)
  161. kvs.put('<service_health>', SERVICE.health)
  162. kvs.put('<configmap_env_name>', configmap_env_name)
  163. k3sUtils.generateDeployment(kvs, 'deployment.yaml')
  164. k3sUtils.applyDeployment(K3S, 'deployment.yaml')
  165. k3sUtils.generateService(kvs, 'service.yaml')
  166. k3sUtils.applyService(K3S, 'service.yaml')
  167. }
  168. }
  169. def deployWithConfigmapEnvOnly2nd(SERVICE, K3S, String base_branch, String[] args, configmapEnv="./configmap-env.ini", namespace='ahxpm') {
  170. print "loading ${sharedLibsPath}/k3sUtil.groovy..."
  171. def k3sUtils = load "${sharedLibsPath}/k3sUtil.groovy"
  172. def configmap_env_name = k3sUtils.applyConfigMapEnv(SERVICE, K3S, configmapEnv, namespace)
  173. def java_args = '['
  174. args.each{item -> java_args += "\"$item\","}
  175. java_args = java_args[0..-2] + ']'
  176. kvs = [:]
  177. kvs.put('<service_name>', SERVICE.name)
  178. kvs.put('<service_version>', SERVICE.version)
  179. kvs.put('<release>', base_branch)
  180. kvs.put('<COMMIT_SHA>', COMMIT_SHA)
  181. kvs.put('<imagePullSecret>', K3S.pull_secretId)
  182. kvs.put('<docker_image>', imageUri)
  183. kvs.put('<java_args>', java_args)
  184. if (SERVICE.health != null)
  185. kvs.put('<service_health>', SERVICE.health)
  186. kvs.put('<configmap_env_name>', configmap_env_name)
  187. k3sUtils.generateDeployment(kvs, 'deployment2.yaml')
  188. k3sUtils.applyDeployment(K3S, 'deployment2.yaml')
  189. k3sUtils.generateService(kvs, 'service2.yaml')
  190. k3sUtils.applyService(K3S, 'service2.yaml')
  191. }
  192. def deployWithConfigmapEnvOnly2nd_rollback(SERVICE, K3S, String rollbackBuildNumber, String[] args, configmapEnv="./configmap-env.ini", namespace='ahxpm') {
  193. print "loading ${sharedLibsPath}/k3sUtil.groovy..."
  194. def k3sUtils = load "${sharedLibsPath}/k3sUtil.groovy"
  195. dir("${backup_destination}/${JOB_NAME}/${rollbackBuildNumber}/k8s") {
  196. def configmap_env_name = k3sUtils.applyConfigMapEnv(SERVICE, K3S, configmapEnv, namespace)
  197. def java_args = '['
  198. args.each{item -> java_args += "\"$item\","}
  199. java_args = java_args[0..-2] + ']'
  200. kvs = [:]
  201. kvs.put('<service_name>', SERVICE.name)
  202. kvs.put('<service_version>', SERVICE.version)
  203. kvs.put('<release>', BASE_BRANCH)
  204. kvs.put('<COMMIT_SHA>', COMMIT_SHA)
  205. kvs.put('<imagePullSecret>', K3S.pull_secretId)
  206. kvs.put('<docker_image>', imageUri)
  207. kvs.put('<java_args>', java_args)
  208. if (SERVICE.health != null)
  209. kvs.put('<service_health>', SERVICE.health)
  210. kvs.put('<configmap_env_name>', configmap_env_name)
  211. k3sUtils.generateDeployment(kvs, 'deployment2.yaml')
  212. k3sUtils.applyDeployment(K3S, 'deployment2.yaml')
  213. k3sUtils.generateService(kvs, 'service2.yaml')
  214. k3sUtils.applyService(K3S, 'service2.yaml')
  215. }
  216. }
  217. def deployWithConfigmaps_rollback(SERVICE, K3S, String rollbackBuildNumber, String[] args, configmapEnv="./configmap-env.ini", configmapConf="./configmap") {
  218. print "loading ${sharedLibsPath}/k3sUtil.groovy..."
  219. def k3sUtils = load "${sharedLibsPath}/k3sUtil.groovy"
  220. dir("${backup_destination}/${JOB_NAME}/${rollbackBuildNumber}/k8s") {
  221. def configmap_env_name = k3sUtils.applyConfigMapEnv(SERVICE, K3S, configmapEnv)
  222. def configmap_conf_name = k3sUtils.applyConfigMapConfig(SERVICE, K3S, configmapConf)
  223. def java_args = '['
  224. args.each{item -> java_args += "\"$item\","}
  225. java_args = java_args[0..-2] + ']'
  226. kvs = [:]
  227. kvs.put('<service_name>', SERVICE.name)
  228. kvs.put('<service_version>', SERVICE.version)
  229. kvs.put('<release>', BASE_BRANCH)
  230. kvs.put('<COMMIT_SHA>', COMMIT_SHA)
  231. kvs.put('<imagePullSecret>', K3S.pull_secretId)
  232. kvs.put('<docker_image>', imageUri)
  233. kvs.put('<java_args>', java_args)
  234. if (SERVICE.health != null)
  235. kvs.put('<service_health>', SERVICE.health)
  236. kvs.put('<configmap_env_name>', configmap_env_name)
  237. kvs.put('<configmap_conf_name>', configmap_conf_name)
  238. k3sUtils.generateDeployment(kvs, 'deployment.yaml')
  239. k3sUtils.applyDeployment(K3S, 'deployment.yaml')
  240. k3sUtils.generateService(kvs, 'service.yaml')
  241. k3sUtils.applyService(K3S, 'service.yaml')
  242. }
  243. }
  244. def deployWithConfigmaps(SERVICE, K3S, String base_branch, String[] args, configmapEnv="./configmap-env.ini", configmapConf="./configmap") {
  245. print "loading ${sharedLibsPath}/k3sUtil.groovy..."
  246. def k3sUtils = load "${sharedLibsPath}/k3sUtil.groovy"
  247. def configmap_env_name = k3sUtils.applyConfigMapEnv(SERVICE, K3S, configmapEnv)
  248. def configmap_conf_name = k3sUtils.applyConfigMapConfig(SERVICE, K3S, configmapConf)
  249. def java_args = '['
  250. args.each{item -> java_args += "\"$item\","}
  251. java_args = java_args[0..-2] + ']'
  252. kvs = [:]
  253. kvs.put('<service_name>', SERVICE.name)
  254. kvs.put('<service_version>', SERVICE.version)
  255. kvs.put('<release>', base_branch)
  256. kvs.put('<COMMIT_SHA>', COMMIT_SHA)
  257. kvs.put('<imagePullSecret>', K3S.pull_secretId)
  258. kvs.put('<docker_image>', imageUri)
  259. kvs.put('<java_args>', java_args)
  260. if (SERVICE.health != null)
  261. kvs.put('<service_health>', SERVICE.health)
  262. kvs.put('<configmap_env_name>', configmap_env_name)
  263. kvs.put('<configmap_conf_name>', configmap_conf_name)
  264. k3sUtils.generateDeployment(kvs, 'deployment.yaml')
  265. k3sUtils.applyDeployment(K3S, 'deployment.yaml')
  266. k3sUtils.generateService(kvs, 'service.yaml')
  267. k3sUtils.applyService(K3S, 'service.yaml')
  268. }
  269. def deployWithConfigmaps2nd(SERVICE, K3S, String base_branch, String[] args, configmapEnv="./configmap-env.ini", configmapConf="./configmap") {
  270. print "loading ${sharedLibsPath}/k3sUtil.groovy..."
  271. def k3sUtils = load "${sharedLibsPath}/k3sUtil.groovy"
  272. def configmap_env_name = k3sUtils.applyConfigMapEnv(SERVICE, K3S, configmapEnv)
  273. def configmap_conf_name = k3sUtils.applyConfigMapConfig(SERVICE, K3S, configmapConf)
  274. def java_args = '['
  275. args.each{item -> java_args += "\"$item\","}
  276. java_args = java_args[0..-2] + ']'
  277. kvs = [:]
  278. kvs.put('<service_name>', SERVICE.name)
  279. kvs.put('<service_version>', SERVICE.version)
  280. kvs.put('<release>', base_branch)
  281. kvs.put('<COMMIT_SHA>', COMMIT_SHA)
  282. kvs.put('<imagePullSecret>', K3S.pull_secretId)
  283. kvs.put('<docker_image>', imageUri)
  284. kvs.put('<java_args>', java_args)
  285. if (SERVICE.health != null)
  286. kvs.put('<service_health>', SERVICE.health)
  287. kvs.put('<configmap_env_name>', configmap_env_name)
  288. kvs.put('<configmap_conf_name>', configmap_conf_name)
  289. k3sUtils.generateDeployment(kvs, 'deployment2.yaml')
  290. k3sUtils.applyDeployment(K3S, 'deployment2.yaml')
  291. k3sUtils.generateService(kvs, 'service2.yaml')
  292. k3sUtils.applyService(K3S, 'service2.yaml')
  293. }
  294. // Jenkins pipeline stages
  295. def execute(CONFIG, base_branch, closures=[:]) { //配置文件,当前分支,自定义闭包
  296. stage('source code check out') {
  297. println "loading ${sharedLibsPath}/gitUtil.groovy..." //打印信息共享库路径,变量路径,存储加载的录像本身地址,脚本名称
  298. def gitUtils = load "${sharedLibsPath}/gitUtil.groovy" //load方法加载对象,赋值给gitUtils
  299. COMMIT_SHA = closures.GITCLONE == null ? gitUtils.clone(CONFIG.git, base_branch) : closures.GITCLONE() //定义变量,为空则调用git配置中git仓库信息branch当前分支,不空调用自定义闭包
  300. }
  301. stage("docker image build") {
  302. def projDir = 'projdir' //定义变量,项目目录
  303. if (closures.BUILDJAR != null) //检查是否自定义闭包,有就使用,没有就使用默认方法
  304. projDir = closures.BUILDJAR()
  305. else
  306. projDir = buildJar(CONFIG.service, projDir) //ahxpm
  307. if (closures.BACKUP != null)
  308. closures.BACKUP()
  309. if (closures.GENERATEDOCKERFILE != null)
  310. projDir = closures.GENERATEDOCKERFILE()
  311. else
  312. projDir = generateDockerfile(CONFIG.service) //ahxpm
  313. if (closures.BUILDIMAGE != null)
  314. imageUri = closures.BUILDIMAGE()
  315. else
  316. imageUri = buildDockerImage(CONFIG.service, CONFIG.docker, base_branch, projDir)
  317. if (closures.CLEANJAR != null)
  318. closures.CLEANJAR()
  319. else
  320. cleanJar(projDir)
  321. }
  322. stage("notify when build") {
  323. //notifywhenbuild(base_branch, CONFIG.service.name)
  324. }
  325. stage("apply K8S ConfigMaps && Deployment") {
  326. if (closures.K3SDEPLOY != null) {
  327. closures.K3SDEPLOY()
  328. return
  329. }
  330. }
  331. }
  332. def upgrade(Object CONFIG, String base_branch, String[] k8sBackupFiles, closures=[:]) {
  333. stage('source code check out') {
  334. println "loading ${sharedLibsPath}/gitUtil.groovy..."
  335. def gitUtils = load "${sharedLibsPath}/gitUtil.groovy"
  336. COMMIT_SHA = closures.GITCLONE == null ? gitUtils.clone(CONFIG.git, base_branch) : closures.GITCLONE()
  337. if (closures.POST_GITCLONE != null)
  338. closures.POST_GITCLONE()
  339. }
  340. stage("docker image build") {
  341. def projDir = 'projdir'
  342. if (closures.BUILDJAR != null)
  343. projDir = closures.BUILDJAR()
  344. else
  345. projDir = buildJar(CONFIG.service, projDir) //ahxpm
  346. if (closures.GENERATEDOCKERFILE != null)
  347. projDir = closures.GENERATEDOCKERFILE()
  348. else
  349. projDir = generateDockerfile(CONFIG.service) //ahxpm
  350. if (closures.BUILDIMAGE != null)
  351. imageUri = closures.BUILDIMAGE()
  352. else
  353. imageUri = buildDockerImage(CONFIG.service, CONFIG.docker, base_branch, projDir)
  354. if (closures.CLEANJAR != null)
  355. closures.CLEANJAR()
  356. else
  357. cleanJar(projDir)
  358. // stage("Docker Image backup") {
  359. if (k8sBackupFiles != null && k8sBackupFiles.size() > 0) {
  360. backupDockerImage(imageUri)
  361. envFile = new File("${backup_destination}/${JOB_NAME}/${BUILD_NUMBER}/env")
  362. envFile << "${COMMIT_SHA}\n"
  363. envFile << "${base_branch}\n"
  364. }
  365. // }
  366. cleanDockerImage(imageUri)
  367. }
  368. stage("apply K8S ConfigMaps && Deployment") {
  369. // stage("K8s configs backup") {
  370. if (k8sBackupFiles != null && k8sBackupFiles.size() > 0)
  371. backupK8sConfigs(k8sBackupFiles)
  372. // }
  373. if (closures.K3SDEPLOY != null) {
  374. closures.K3SDEPLOY()
  375. return
  376. }
  377. }
  378. stage("notify when build") {
  379. if (closures.BUILDINFO != null) {
  380. def buildInfo = closures.ALLCHANGES()
  381. if (buildInfo.length() > 800) {
  382. buildInfo = buildInfo.substring(buildInfo.length() - 800)
  383. }
  384. def title = closures.BUILDINFO()+"正在发布"
  385. def content = "变更:"+buildInfo+"\\n"+
  386. "分支:"+base_branch+"\\n"+
  387. "版本:"+BUILD_NUMBER+"\\n"
  388. sendGroupNotification(title, content)
  389. }
  390. }
  391. stage("Post Execution Script") {
  392. print "Clear older backup version"
  393. // 清理旧的备份
  394. dir("${backup_destination}/${JOB_NAME}") {
  395. sh """
  396. save_file=`ls -ltr | tail -${BACKUP_MAX} | awk '{print \$NF}'`
  397. ls | grep -v "\$save_file" | xargs rm -rf
  398. """
  399. }
  400. }
  401. }
  402. def rollback(CONFIG, rollbackBuildNumber, closures=[:]) {
  403. // 1. restore specified version
  404. path = "${backup_destination}/${JOB_NAME}/${rollbackBuildNumber}"
  405. if (fileExists(path)) {
  406. stage('source code check out') {
  407. print("souce code check out. Skipped!")
  408. }
  409. envFile = new File("${backup_destination}/${JOB_NAME}/${rollbackBuildNumber}/env")
  410. def lines = envFile.readLines()
  411. COMMIT_SHA = lines[0]
  412. BASE_BRANCH = lines[1]
  413. // 2. docker image build
  414. stage("docker image build") {
  415. print("restore docker image from rollbackNo. #${rollbackBuildNumber}")
  416. imageUri = restoreDockerImage(CONFIG.docker, path, BASE_BRANCH, rollbackBuildNumber)
  417. cleanDockerImage(imageUri)
  418. }
  419. // 3. k8s configmap && deployment apply
  420. stage("apply K8S ConfigMaps && Deployment") {
  421. if (closures.K3SDEPLOY != null)
  422. closures.K3SDEPLOY()
  423. }
  424. stage("Post Execution Script") {
  425. print "Clear rollback workspace"
  426. // 清理rollback工作目录
  427. dir("${backup_destination}/${JOB_NAME}") {
  428. sh "rm -rf *@tmp"
  429. }
  430. }
  431. }
  432. }
  433. def sendGroupNotification(String title, String content) {
  434. WECHAT_ROBOT_URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=92059925-97db-4830-8438-1514a246a143"
  435. stage('Send Message') {
  436. // 构建要发送的企业微信消息
  437. def message = """
  438. {
  439. "msgtype": "text",
  440. "text": {
  441. "content": "【${title}】\n${content}"
  442. }
  443. }
  444. """
  445. // 发送消息到企业微信
  446. sh """
  447. curl -X POST -H 'Content-Type: application/json' -d '${message}' ${WECHAT_ROBOT_URL}
  448. """
  449. }
  450. }
  451. return this