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系列(一)-- 如何配置扩展共享库
流程说明
- 编译
- 预览(按需登录)
- 上传(按需登录)
Pipeline实现
这里还是使用的是Jenkins的扩展共享库来实现的,在上面有共享扩展库的文章说明,请参考
在共享扩展库的Git Repo的vars目录下新建wechat_mini_program_build.groovy,内容如下:
/**
配置参数说明:
--------------------------------------------------------------
参数名称: REPO_URL
参数类型: 文本参数
默认值: ssh://[email protected]/group_name/repo_name.git
描述: 项目代码仓库地址
--------------------------------------------------------------
参数名称: BUILD_BRANCH
参数类型: 字符参数
默认值: some-branch
描述: 构建分支
some-branch
develop
release
master
--------------------------------------------------------------
参数名称: BUILD_ENV
参数类型: Active Choices Parameter
Groovy Script: return["请选择","dev","test","prod"]
描述: dev开发环境
test测试环境
prod生产环境
--------------------------------------------------------------
参数名称: BUILD_TYPE
参数类型: 选型参数
选型: preview
upload
描述: preview: 预览生成二维码
upload: 上传代码
--------------------------------------------------------------
参数名称: UPLOAD_VERSION
参数类型: 字符参数
默认值:
描述: 上传代码版本号: 如 2.0.0
只有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}
构建环境: ${BUILD_ENV}
构建类型: ${BUILD_TYPE}
请使用微信扫描以下二维码进行预览:
"
}else{
log.error '执行失败'
closeTool()
buildDesc = '微信开发者工具登录失效,请登录后再执行
登录工具:'
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}
构建环境: ${BUILD_ENV}
构建类型: ${BUILD_TYPE}"
}else{
log.error '上传失败'
closeTool()
buildDesc = '微信开发者工具登录失效,请登录后再执行
登录工具:'
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:'你的项目名称'
)
}
}
打开任务执行,参数如下:
预览任务执行后的样子如下图,打包任务,基本一致,就是没有二维码而已:
小程序的自动化任务,都是需要有登录态的(上面的任务,如果登录失效,会提示,用登录工具先登录),这里登录的动作必须由人工完成,下面是登录工具的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
微信小程序命令行说明