美文网首页前端
Jenkins Pipeline系列(三)—— 使用扩展共享库构

Jenkins Pipeline系列(三)—— 使用扩展共享库构

作者: 天行者YANG | 来源:发表于2020-11-26 17:59 被阅读0次

    Jenkins Pipeline 微信小程序

    手动上传不是挺方便的吗

    在初期,小程序开发者1-2人时,通过Win和Mac小程序开发者工具,进行上传确实比较省时省力,但是随着小程序业务代码增多,并行开发任务增多,开发者增多, 在管理各种版本上,都需要牵扯精力,而且上传发布很可能是多个人都会进行的事情了。我们并不能保证每个上传人的环境统一、AppID每次替换都不出错误等等。随着这些问题的发生,自然而然,我们会把频繁做且流程化的事情,做成自动化。

    环境说明

    硬件

    • Mac Mini(OR Windows本,这里我使用的是Mac Mini)

    软件

    • Jenkins(Docker):Pipeline构建平台
    • Node(v12.13.0) & Npm(6.12.0):编译工具
    • 微信开发者工具:主要依赖工具
    • Nginx(Docker):内网图片服务
    • Gitlab(Docker):代码库

    关于Jenkins、Gitlab,以及Jenkins的扩展共享库,请参考下面的链接
    Jenkins Pipeline系列(一)-- 如何配置扩展共享库

    流程说明

    Jenkins Pipeline 微信小程序 c63d3b7cb57b422d9a0e784fc60593bd.jpg
    • 编译
    • 预览(按需登录)
    • 上传(按需登录)

    Pipeline实现

    这里还是使用的是Jenkins的扩展共享库来实现的,在上面有共享扩展库的文章说明,请参考
    在共享扩展库的Git Repo的vars目录下新建wechat_mini_program_build.groovy,内容如下:

    /**
    配置参数说明:
    --------------------------------------------------------------
    参数名称: REPO_URL
    参数类型: 文本参数
    默认值: ssh://git@gitlab.xxx.com/group_name/repo_name.git
    描述: 项目代码仓库地址
    --------------------------------------------------------------
    参数名称: BUILD_BRANCH
    参数类型: 字符参数
    默认值: some-branch
    描述: 构建分支<br>
         some-branch<br>
         develop<br>
         release<br>
         master
    --------------------------------------------------------------
    参数名称: BUILD_ENV
    参数类型: Active Choices Parameter
    Groovy Script: return["请选择","dev","test","prod"]
    描述: dev开发环境<br>
         test测试环境<br>
         prod生产环境
    --------------------------------------------------------------
    参数名称: BUILD_TYPE
    参数类型: 选型参数
    选型: preview
         upload
    描述: preview: 预览生成二维码<br>
         upload: 上传代码
    --------------------------------------------------------------
    参数名称: UPLOAD_VERSION
    参数类型: 字符参数
    默认值: 
    描述: 上传代码版本号: 如 2.0.0<br>
         只有upload任务需要
    */
    def call(Map config) {
        node('front-end') {
            properties([
                buildDiscarder(
                  logRotator(
                      daysToKeepStr: '30',
                      numToKeepStr: '50'
                  )
              )
            ])
            stage('清理工作区') {
                log.info '清理工作区'
                deleteDir()
            }
            stage('获取代码') {
                log.info "获取代码地址:${REPO_URL},获取代码分支: ${BUILD_BRANCH}"
                fetch_code "${REPO_URL}"
            }
            stage('编译') {
                log.info "构建:${BUILD_ENV}"
                sh "source ~/.bash_profile && npm install && npm run build:${BUILD_ENV}"
            }
            stage('替换APPID'){
                miniProgramAppId = getMiniProgramAppId("${BUILD_ENV}",config.projectName)
                log.info "替换数据:${BUILD_ENV},小程序APPID:${miniProgramAppId}"
                sh "sed -i '' 's/\"appid\":.*/\"appid\": \"${miniProgramAppId}\",/g' ${WORKSPACE}/dist/build/mp-weixin/project.config.json"
            }
            stage('预览') {
                if(BUILD_TYPE == 'preview'){
                    log.info "构建分支: ${BUILD_BRANCH}"
                    wechatBinPath = '/Applications/wechatwebdevtools.app/Contents/MacOS'
                    sh "${wechatBinPath}/cli preview --project ${WORKSPACE}/dist/build/mp-weixin -f image -o ${WORKSPACE}/${BUILD_ID}.jpg > ${WORKSPACE}/build.log"
                    errlog = sh(returnStdout: true, script: "grep -i error: ${WORKSPACE}/build.log || echo").trim()
                    log.info "errlog:${errlog}"
                    if ("${errlog}"==""){
                        log.info '执行成功'
                        sh "cp ${WORKSPACE}/${BUILD_ID}.jpg /Users/guoguo/workspace/nginx/image"
                        buildDesc = "代码分支: ${BUILD_BRANCH}<br>构建环境: ${BUILD_ENV}<br>构建类型: ${BUILD_TYPE}<br>请使用微信扫描以下二维码进行预览: <br><img src=\"http://图片服务器地址/${BUILD_ID}.jpg\" width=\"200\" height=\"200\">"
                    }else{
                        log.error '执行失败'
                        closeTool()
                        buildDesc = '微信开发者工具登录失效,请登录后再执行<br>登录工具:<a href=\"${JENKINS_URL}/job/WECHAT_LOGIN_TOOL\">'
                        sh "exit 1"
                    }
                }else{
                    log.info '不是预览任务,跳过'
                }
            }
            stage('上传') {
                if(BUILD_TYPE == 'upload'){
                    if(BUILD_ENV == 'prod' && BUILD_BRANCH != 'master'){
                        log.error 'PROD环境只能允许master分支上传'
                        sh "exit 1"
                    }
                    log.info "构建分支: ${BUILD_BRANCH}"
                    wechatBinPath = '/Applications/wechatwebdevtools.app/Contents/MacOS'
                    now = getTimestamp()
                    uploadDesc = "CI 在 ${now} 提交上传"
                    sh "${wechatBinPath}/cli upload --project ${WORKSPACE}/dist/build/mp-weixin -v '${UPLOAD_VERSION}' -d '${uploadDesc}' > ${WORKSPACE}/upload.log"
                    errlog = sh(returnStdout: true, script: "grep -i error: ${WORKSPACE}/upload.log || echo").trim()
                    log.info "errlog:${errlog}"
                    if ("${errlog}"==""){
                        log.info '上传成功'
                        buildDesc = "代码分支: ${BUILD_BRANCH}<br>构建环境: ${BUILD_ENV}<br>构建类型: ${BUILD_TYPE}"
                    }else{
                        log.error '上传失败'
                        closeTool()
                        buildDesc = '微信开发者工具登录失效,请登录后再执行<br>登录工具:<a href=\"${JENKINS_URL}/job/登录工具JOB\">'
                        sh "exit 1"
                    }
                }else{
                    log.info '不是上传任务,跳过'
                }
            }
            stage('关闭工具'){
                closeTool()
            }
            stage('通知') {
                dingding.notice("${BUILD_BRANCH}")
            }
            currentBuild.description = "${buildDesc}"
        }
    }
    
    def getMiniProgramAppId(buildEnv,projectEnglishName){
        if(projectEnglishName == '应用A'){
            if(buildEnv == 'dev'){
                miniProgramAppId = 'xxx'
            }else if(buildEnv == 'test'){
                miniProgramAppId = 'xxx'
            }else if(buildEnv == 'prod'){
                miniProgramAppId = 'xxx'
            }
        }
        if(projectEnglishName == '应用B'){
            if(buildEnv == 'dev'){
                miniProgramAppId = 'xxx'
            }else if(buildEnv == 'test'){
                miniProgramAppId = 'xxx'
            }else if(buildEnv == 'prod'){
                miniProgramAppId = 'xxx'
            }
        }
        if(projectEnglishName == '应用C'){
            if(buildEnv == 'dev'){
                miniProgramAppId = 'xxx'
            }else if(buildEnv == 'test'){
                miniProgramAppId = 'xxx'
            }else if(buildEnv == 'prod'){
                miniProgramAppId = 'xxx'
            }
        }
        return miniProgramAppId
    }
    
    def closeTool(){
        log.info "关闭工具"
        sh "${wechatBinPath}/cli quit"
    }
    
    def getTimestamp() {
        return new Date().format('yyyy-MM-dd HH:mm:ss')
    }
    

    在Jenkins新建JOB,类型选择Pipeline,按照上面脚本注释内的“配置参数说明”,录入参数,并在最下面,Pipeline script填写如下内容,点击保存:

    @Library('jenkins-shared-libraries@master') _
    
    node {
        script {
            wechat_mini_program_build(
                projectName:'你的项目名称'
            )
        }
    }
    

    打开任务执行,参数如下:


    20201126171008.jpg

    预览任务执行后的样子如下图,打包任务,基本一致,就是没有二维码而已:


    20201126171901.jpg

    小程序的自动化任务,都是需要有登录态的(上面的任务,如果登录失效,会提示,用登录工具先登录),这里登录的动作必须由人工完成,下面是登录工具的Pipeline,vars 下面新建wechat_mini_program_login_tool.groovy

    def call() {
        node('front-end') {
            properties([
                buildDiscarder(
                  logRotator(
                      daysToKeepStr: '30',
                      numToKeepStr: '50'
                  )
              )
            ])
            stage('登录') {
                log.info "登录"
                imagePath = '/你的图片Nginx目录'
                wechatBinPath = '/Applications/wechatwebdevtools.app/Contents/MacOS'
                sh "${wechatBinPath}/cli login -f image -o ${imagePath}/login-${BUILD_ID}.jpg > ${WORKSPACE}/run.log 2>&1 &"
                log.info "请在60秒内打开链接并扫码(请使用专用微信): http://图片服务器地址/login-${BUILD_ID}.jpg"
                sh 'sleep 60'
            }
        }
    }
    

    在Jenkins新建JOB,类型选择Pipeline,并在最下面,Pipeline script填写如下内容,点击保存:

    @Library('jenkins-shared-libraries@master') _
    
    node {
        script {
            wechat_mini_program_login_tool()
        }
    }
    

    构建过程中,点击控制台打印的 http://图片服务器地址/login-${BUILD_ID}.jpg链接,进行扫描动作

    总结

    已经解决问题

    • 自动化编译
    • 自动化预览
    • 自动化上传代码

    TODO

    • 自动从package.json读取版本号并做自动新增
    • 自动MR / 自动Tag

    Reference

    微信小程序命令行说明

    Jenkins Pipeline系列(一)—— 如何配置扩展共享库
    Jenkins Pipeline系列(二)—— 使用扩展共享库构建Maven项目
    Jenkins Pipeline系列(三)—— 使用扩展共享库构建微信小程序项目

    相关文章

      网友评论

        本文标题:Jenkins Pipeline系列(三)—— 使用扩展共享库构

        本文链接:https://www.haomeiwen.com/subject/ojdziktx.html