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系列(一)– 如何配置扩展共享库
流程说明
![](/images/2020-11/mini-program-flow.jpg)
Pipeline实现
这里还是使用的是Jenkins的扩展共享库来实现的,在上面有共享扩展库的文章说明,请参考
在共享扩展库的Git Repo的vars目录下新建wechat_mini_program_build.groovy,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
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填写如下内容,点击保存:
1 2 3 4 5 6 7 8 9
| @Library('jenkins-shared-libraries@master') _
node { script { wechat_mini_program_build( projectName:'你的项目名称' ) } }
|
打开任务执行,参数如下:
![](/images/2020-11/mini-program-pipeline-build.jpg)
预览任务执行后的样子如下图,打包任务,基本一致,就是没有二维码而已:
![](/images/2020-11/mini-program-result.jpg)
小程序的自动化任务,都是需要有登录态的(上面的任务,如果登录失效,会提示,用登录工具先登录),这里登录的动作必须由人工完成,下面是登录工具的Pipeline,vars 下面新建wechat_mini_program_login_tool.groovy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 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填写如下内容,点击保存:
1 2 3 4 5 6 7
| @Library('jenkins-shared-libraries@master') _
node { script { wechat_mini_program_login_tool() } }
|
构建过程中,点击控制台打印的 http://图片服务器地址/login-${BUILD_ID}.jpg链接,进行扫描动作
总结
已经解决问题
TODO
- 自动从package.json读取版本号并做自动新增
- 自动MR / 自动Tag
Reference
微信小程序命令行说明