首页 > 其他分享 >手把手教你如何实现企业微信Jenkins 构建发布通知

手把手教你如何实现企业微信Jenkins 构建发布通知

时间:2023-08-27 20:31:50浏览次数:37  
标签:构建 name NAME 手把手 export BUILD 微信 Jenkins USER

一.前言

在企业项目发版本过程中,以Jenkins为例,个别项目构建时间较长,不想时刻关注构建情况,或构建成功后移交其他人继续处理,需要配置企业微信通知功能,本篇主要是针对pipeline流水线项目,如何实现Jenkins构建成功与否通知到消息至企业微信指定人

二.实现过程

2.1 企业微信创建机器人

这里采用比较简单的方法实现,主要是通过Pipeline+Shell, Pipeline对shell还是比较有好的,这里首先必须要选择企业微信,创建2~3人以上的群聊,随后添加一个群机器人

手把手教你如何实现企业微信Jenkins 构建发布通知_Jenkins

创建机器人主要是为了接收我们传递的消息和提供一个控制它的API,这里我们只需要记住机器人的webhook,下面的shell脚本将会通过webhook的方式调用它

手把手教你如何实现企业微信Jenkins 构建发布通知_Jenkins_02

2.2 Jenkins安装插件

关于企业微信构建任务通知,Jenkins需要依赖以下插件

获取构建用户变量  需安装插件: build user vars plugin
获取构建时间变量  需安装插件:Build Timestamp Plugin
企业微信插件 Qy Wechat Notification

2.3 编写Shell脚本

Shell脚本主要用于请求企业微信API、发送数据等

#vim send_message-export.sh
#!/bin/sh
#替换成自己的群机器人key值
CHAT_WEBHOOK_KEY=xxxxxx-xxxxxx-xxxxxx-xxxxxxxx
CHAT_CONTENT_TYPE='Content-Type: application/json'
#-o代表或的意思,成功或失败 CHAT_WEBHOOK_URL都是一样的WEBHOOK url
if [ _"${TYPE}" = _"success" -o  _"${TYPE}" = _"failure" ]; then
  CHAT_WEBHOOK_URL='https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key'
fi

if [ _"${CHAT_WEBHOOK_KEY}" = _"" ]; then
  echo "please make sure CHAT_WEBHOOK_KEY has been exported as environment variable"

fi
echo "## send message for : ${TYPE}"
if [ _"${TYPE}" = _"success" ]; then
  curl "${CHAT_WEBHOOK_URL}=${CHAT_WEBHOOK_KEY}" \
   -H "${CHAT_CONTENT_TYPE}" \
   -d '
   {
        "msgtype": "markdown",
        "markdown": {
         "content": "<font color=\"warning\">**Jenkins任务通知**</font> \n
         >构建人:<font color=\"comment\">'"${BUILD_USER}"'</font>
         >构建时间:<font color=\"comment\">'"${BUILD_TIME}"'</font>
         >构建分支:<font color=\"comment\">'"${BRANCH_NAME}"'</font>
         >任务名称:<font color=\"comment\">'"${JOB_NAME}"'</font>
         >构建次数:<font color=\"comment\">'"${BUILD_NUM}"'</font>
         >任务地址:<font color=\"comment\">[点击查看]('"${URL_JOB}"')</font>
         >构建日志:<font color=\"comment\">[点击查看]('"${URL_LOG}"')</font>
         >构建状态:<font color=\"info\">**Success**</font> \n
         >任务已构建完成请确认:<@'"${BUILD_USER}"'>"
         
        }
   }
'
elif [ _"${TYPE}" = _"failure" ]; then
  curl "${CHAT_WEBHOOK_URL}=${CHAT_WEBHOOK_KEY}" \
   -H "${CHAT_CONTENT_TYPE}" \
   -d '
   {
        "msgtype": "markdown",
        "markdown": {
         "content": "<font color=\"warning\">**Jenkins任务通知**</font> \n
         >构建人:<font color=\"comment\">'"${BUILD_USER}"'</font>
         >构建时间:<font color=\"comment\">'"${BUILD_TIME}"'</font>
         >构建分支:<font color=\"comment\">'"${BRANCH_NAME}"'</font>
         >任务名称:<font color=\"comment\">'"${JOB_NAME}"'</font>
         >构建次数:<font color=\"comment\">'"${BUILD_NUM}"'</font>
         >任务地址:<font color=\"comment\">[点击查看]('"${URL_JOB}"')</font>
         >构建日志:<font color=\"comment\">[点击查看]('"${URL_LOG}"')</font>
         >构建状态:<font color=\"comment\">**Failure**</font>
         >任务已构建完成请确认:<@'"${BUILD_USER}"'>"
         
        }
   }
'
fi

2.4 Pipeline脚本

在这里我这边给出整个pipeline企业微信消息通知流水线案例

#vim Jenkinsfile
pipeline {
  agent {
    kubernetes {
      cloud 'Test-kubernetes'
      slaveConnectTimeout 1200
      workspaceVolume hostPathWorkspaceVolume(hostPath: "/opt/workspace", readOnly: false)
      yaml '''
apiVersion: v1
kind: Pod
spec:
  containers:
    - args: [\'$(JENKINS_SECRET)\', \'$(JENKINS_NAME)\']
      image: 'registry.cn-beijing.aliyuncs.com/devops-tols/jnlp-slave:latest'
      name: jnlp
      imagePullPolicy: IfNotPresent
      volumeMounts:
        - mountPath: "/etc/localtime"
          name: "localtime"
          readOnly: false
    - command:
        - "cat"
      env:
        - name: "LANGUAGE"
          value: "en_US:en"
        - name: "LC_ALL"
          value: "en_US.UTF-8"
        - name: "LANG"
          value: "en_US.UTF-8"
      image: "registry.cn-beijing.aliyuncs.com/devops-tols/maven:3.5.3"
      imagePullPolicy: "IfNotPresent"
      name: "build"
      tty: true
      volumeMounts:
        - mountPath: "/etc/localtime"
          name: "localtime"
        - mountPath: "/root/.m2/"
          name: "cachedir"
          readOnly: false
    - command:
        - "cat"
      env:
        - name: "LANGUAGE"
          value: "en_US:en"
        - name: "LC_ALL"
          value: "en_US.UTF-8"
        - name: "LANG"
          value: "en_US.UTF-8"
      image: "registry.cn-beijing.aliyuncs.com/devops-tols/kubectl:self-1.17"
      imagePullPolicy: "IfNotPresent"
      name: "kubectl"
      tty: true
      volumeMounts:
        - mountPath: "/etc/localtime"
          name: "localtime"
          readOnly: false
    - command:
        - "cat"
      env:
        - name: "LANGUAGE"
          value: "en_US:en"
        - name: "LC_ALL"
          value: "en_US.UTF-8"
        - name: "LANG"
          value: "en_US.UTF-8"
      image: "registry.cn-beijing.aliyuncs.com/devops-tols/docker-git:1.19-git"
      imagePullPolicy: "IfNotPresent"
      name: "docker"
      tty: true
      volumeMounts:
        - mountPath: "/etc/localtime"
          name: "localtime"
          readOnly: false
        - mountPath: "/var/run/docker.sock"
          name: "dockersock"
          readOnly: false
  restartPolicy: "Never"
  nodeSelector:
    jenkins-build: "true"
  securityContext: {}
  volumes:
    - hostPath:
        path: "/var/run/docker.sock"
      name: "dockersock"
    - hostPath:
        path: "/usr/share/zoneinfo/Asia/Shanghai"
      name: "localtime"
    - name: "cachedir"
      hostPath:
        path: "/opt/m2"
'''
    }
}
  stages {
    stage('Pulling Code') {
      parallel {
        stage('Pulling Code by Jenkins') {
          when {
            expression {
              env.gitlabBranch == null
            }

          }
          steps {
            git(changelog: true, poll: true, url: 'https://gitee.com/bjcaszyx/test-boot-projext.git', branch: "${BRANCH}", credentialsId: 'GITEE_ACCOUNT')
            script {
              COMMIT_ID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
              TAG = BUILD_TAG + '-' + COMMIT_ID
              println "Current branch is ${BRANCH}, Commit ID is ${COMMIT_ID}, Image TAG is ${TAG}"

            }

          }
        }

        stage('Pulling Code by trigger') {
          when {
            expression {
              env.gitlabBranch != null
            }

          }
          steps {
            git(url: 'https://gitee.com/bjcaszyx/test-boot-projext.git', branch: env.gitlabBranch, changelog: true, poll: true, credentialsId: 'GITEE_ACCOUNT')
            script {
              COMMIT_ID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
              TAG = BUILD_TAG + '-' + COMMIT_ID
              println "Current branch is ${env.gitlabBranch}, Commit ID is ${COMMIT_ID}, Image TAG is ${TAG}"
            }

          }
        }

      }
    }

    stage('Building') {
      steps {
//配置构建人变量,在编译阶段定义
        wrap([$class: 'BuildUser']) {
           script {
                BUILD_USER = "${env.BUILD_USER}"
                BUILD_USER_ID ="${BUILD_USER_ID}"
                    }
          }
          script {
                env.BUILD_USERNAME = "${BUILD_USER}"
                env.BUILD_USERNAMEID = "${BUILD_USER_ID}"
                       }
//END结束
        container(name: 'build') {
            sh """
            mvn clean package -Dmaven.test.skip=true -Ptest
            ls target/*
            """
        }
      }
    }

    stage('Docker build for creating image') {
      environment {
        HARBOR_USER = credentials('HARBOR_ACCOUNT')
    }
      steps {
//配置构建人变量,在打包镜像定义
        wrap([$class: 'BuildUser']) {
           script {
                BUILD_USER = "${env.BUILD_USER}"
                BUILD_USER_ID ="${BUILD_USER_ID}"
                    }
          }
          script {
                env.BUILD_USERNAME = "${BUILD_USER}"
                env.BUILD_USERNAMEID = "${BUILD_USER_ID}"
                       }
//END
        container(name: 'docker') {
          sh """
          echo ${HARBOR_USER_USR} ${HARBOR_USER_PSW} ${TAG}
          pwd 
          ls *
          docker version
          docker build -t ${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG} .
          docker login -u ${HARBOR_USER_USR} -p ${HARBOR_USER_PSW} ${HARBOR_ADDRESS}
          docker push ${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG}
          """
        }
      }
    }

    stage('Deploying to K8s') {
      environment {
        MY_KUBECONFIG = credentials('k8s-kubeconfig')
    }
      steps {
//配置构建人变量,在部署环节定义
        wrap([$class: 'BuildUser']) {
           script {
                BUILD_USER = "${env.BUILD_USER}"
                BUILD_USER_ID ="${BUILD_USER_ID}"
                    }
          }
          script {
                env.BUILD_USERNAME = "${BUILD_USER}"
                env.BUILD_USERNAMEID = "${BUILD_USER_ID}"
                       }
//END
        container(name: 'kubectl'){
           sh """
           /usr/local/bin/kubectl --kubeconfig $MY_KUBECONFIG set image deploy -l app=${IMAGE_NAME} ${IMAGE_NAME}=${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG} -n $NAMESPACE
           """
        }
      }
    }

  }    
//下面是整个流水线脚本构建完成之后的动作,这里添加到了pipeline的最下面
      post {
        success {
          container('jnlp'){
       script {
       //多分支流水线项目使用${JOB_NAME}可显示 项目名称+分支名称
          sh 'export TYPE=success;export BRANCH_NAME="${BRANCH}";export JOB_NAME="${JOB_BASE_NAME}";export BUILD_NUM="$BUILD_NUMBER";export BUILD_TIME="$BUILD_TIMESTAMP"; export BUILD_USER="${BUILD_USERNAME}"; export URL_JOB="${BUILD_URL}";export URL_LOG="${BUILD_URL}console";export JOB_TIPS1="${BUILD_USERNAMEID}" ;sh send_message-export.sh'
        }
    }
    }
   failure {
     container('jnlp'){
      script {
        sh 'export TYPE=failure;export BRANCH_NAME="${BRANCH}";export JOB_NAME="${JOB_BASE_NAME}";export BUILD_NUM="$BUILD_NUMBER";export BUILD_TIME="$BUILD_TIMESTAMP"; export BUILD_USER="${BUILD_USERNAME}"; export URL_JOB="${BUILD_URL}";export URL_LOG="${BUILD_URL}console";export JOB_TIPS1="${BUILD_USERNAMEID}" ;sh send_message-export.sh'
      }
    }
  }
  }
//END结束

  environment {
    COMMIT_ID = ""
    HARBOR_ADDRESS = "harbor.xxx.xxx" #这里指定自己的镜像仓库地址
    REGISTRY_DIR = "trt-test"
    IMAGE_NAME = "test-boot-project"
    NAMESPACE = "tongrentang"
    TAG = ""
  }
  parameters {
    gitParameter(branch: '', branchFilter: 'origin/(.*)', defaultValue: '', description: 'Branch for build and deploy', name: 'BRANCH', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'PT_BRANCH')
  //string(defaultValue: 'master', description: 'Branch for build and deploy', name: 'BRANCH')
}
}

Ps: 上述pipeline脚本、Shell脚本都是需要放在git上,保证jenkinsfile能够调用shell脚本

2.5 原理剖析

  • Jenkins通过Jenkinsfike文件构建任务
  • Jenkins文件最后使用了post参数,从而来判断该任务状态(是否正常success/failure)然后调用事先准备好的shell脚本,然后将Jenkins构建过程中获取的参数传递至shell脚本里面
  • 当pipeline流程结束之后,会触发post执行shell脚本,将请求企业微信机器人webhook,发送信息到企业微信群聊中

三、验证测试

Ps:记住一定要在jenkins中确认下时间戳,避免出现构建完成之后企业微信消息通知时间不对

系统管理-->系统配置--Build Timestamp

手把手教你如何实现企业微信Jenkins 构建发布通知_docker_03

整个流水线走下来,发布完成之后就会发送企业微信消息

手把手教你如何实现企业微信Jenkins 构建发布通知_docker_04

手把手教你如何实现企业微信Jenkins 构建发布通知_docker_05

四、问题小思考?

最后虽然整个流程下来都没有问题,细心的小伙伴可能会发现,在Pipeline脚本中,每一个阶段我都定义了构建人环境变量,如果只定义某一处的话,那么在另外某一阶段失败的情况下虽然消息通知了,但是该阶段获取不了构建人变量,企业微信通知消息就会缺失变量(如下图所示)

所以请问对pipeline非常熟悉的小伙伴没有办法解决这个问题,就是说wrap只需要在pipeline一个地方定义即可,此后无论哪阶段构建失败,构建人变量都正常识别,也就能正常的发送完整的消息通知

手把手教你如何实现企业微信Jenkins 构建发布通知_docker_06

手把手教你如何实现企业微信Jenkins 构建发布通知_Jenkins_07

标签:构建,name,NAME,手把手,export,BUILD,微信,Jenkins,USER
From: https://blog.51cto.com/u_11880730/7254507

相关文章

  • 微信小程序 type="nickname" 点击后,获取不到最新值
    在uniapp开发微信小程序,或是使用小程序开发平台开发,会涉及到获取用户的头像和昵称,而在最新的微信小程序基础库,getUserInfo等不能在获取这些信息,官方推荐使用头像昵称填写能力(基础库2.21.2版本开始支持,覆盖iOS与安卓微信8.0.16以上版本),下面讲讲我在使用过程中遇到的问题。<bu......
  • vue微信H5项目使用腾讯地图获取当前位置经纬度
    1.在index.html引入js文件<scriptsrc="https://3gimg.qq.com/lightmap/components/geolocation/geolocation.min.js"></script>2.在需要页面中你自己的key要去腾讯地图工具去申请https://lbs.qq.com/webApi/component/componentGuide/componentPickercreated(){this.getM......
  • Pytest+Jenkins 学习笔记
    Pytest+Jenkins学习笔记在软件测试工作中,单元测试通常是由开发人员执行的、针对最小单元粒度的组件测试,在完成了单元粒度的测试任务之后,通常就需要交由专职的测试人员将这些单元级的组件放到粒度更大的功能组件或子系统中来进行整合性的测试了。在专业术语中,粒度介于单元测试与......
  • Winform微信扫码支付
    微信扫码支付引用的是第三方的:Senparc.Weixin引用:usingSenparc.Weixin.MP.TenPayLibV3;首先,在Form_Load里面调用生成支付二维码的方法:///<summary>///Form_Load事件///</summary>///<paramname="sender"></param>///<......
  • 微信开发之一键邀请好友加入群聊的技术实现
    邀请群成员(开启群验证)若群开启邀请确认,仅能通过本接口邀请群成员请求URL:http://域名/addChatRoomMemberVerify请求方式:POST请求头Headers:Content-Type:application/jsonAuthorization:login接口返回参数:参数名必选类型说明wId是String登录实例标识chatRoomId是String群iduserList是nu......
  • 微信开发之一键修改群聊备注的技术实现
    修改群备注修改群名备注后,如看到群备注未更改,是手机缓存问题,可以连续点击进入其他群,在点击进入修改的群,再返回即可看到修改后的群备注名,群名称的备注仅自己可见请求URL:http://域名地址/modifyGroupRemark请求方式:POST请求头Headers:Content-Type:application/jsonAuthorization:login......
  • 微信开发之一键修改群聊备注的技术实现
    修改群备注 修改群名备注后,如看到群备注未更改,是手机缓存问题,可以连续点击进入其他群,在点击进入修改的群,再返回即可看到修改后的群备注名,群名称的备注仅自己可见请求URL:http://域名地址/modifyGroupRemark请求方式:POST请求头Headers:Content-Type:application/json......
  • 微信开发之一键创建微信群聊的技术实现
    创建微信群本接口为敏感接口,请查阅调用规范手册创建后,手机上不会显示该群,往该群主动发条消息显示。请求URL:http://域名地址/createChatroom请求方式:POST请求头Headers:Content-Type:application/jsonAuthorization:login接口返回参数:参数名必选类型说明wId是String登录实例标识userLis......
  • 实现windows客户端微信多开
    实现windows客户端微信多开1、右键点击微信图标——属性——目标,复制下来2、右键——新建txt文件3、打开txt文件——输入以下内容:@echooffstart"""C:\ProgramFiles(x86)\Tencent\WeChat\WeChat.exe"start"""C:\ProgramFiles(x86)\Tencent\WeChat\WeCha......
  • c# WinForm--微信Native支付
    c#WinForm--微信Native支付 一、了解Native支付流程我用的是模式二,模式二的流程如下二、如何将Demo用在我的WinForm里面打开Demo工程,复制里面的lib、third文件夹到我的工程下,添加引用,引用的内容就是third文件夹里的。还有Demo里面的business文件夹,里面的代码可以参考(复......