【小程序】微信,支付宝小程序中的CI/CD,不要再让别人打断你的开发思路了!

本文内容均只用于支付宝和微信小程序

背景

先说一下为什么要做这个东西把。

  • 基于提审

    • 原生小程序中漫长的提审流程,合PR,切到主分支,pull代码,点击上传,后台提审
    • 原生小程序基于config文件决定抛出环境,提审时项目环境完全靠人工校验

  • 基于测试

    • 测试bugfix校验或者后端同学需要测试环境时,通常都是直接跟我们要二维码,这时我们可能在开发别的项目,本地代码不纯净,所以普遍我们都是commit本地代码,切到干净的分支,然后切好测试环境,在生成二维码给到他们,然后再切回开发分支。这也太麻烦了吧。所以我们开发了一个生成小程序二维码的平台,可以让他们完成脱离我们
    • 测试同学可能对git不熟悉,而且对怎么切换环境也不熟悉

就是基于上面这几点原因让我们基于支付宝和微信提供的SDK开发了属于我们小程序的CI/CD,尽最大可能解放一些繁琐且打断我们思路的工作

功能介绍

  • 自动上传小程序后台,PR合并后触发

    • 校验环境,version自增1(根据自己的项目自行补充需要的校验和功能)
    • 上传完成后叮叮通知,通知信息包括version,体验版二维码,包信息

  • 小程序预览平台

    • 用户体系:普通(可构建),管理员(可上传),超管(可添加用户)
    • 获取所有分支,可切分支
    • 获取当前环境,可切换环境
    • 定义入口页
    • 定义入口页参数
    • 构建预览二维码
    • 管理员以上可手动上传

【小程序】微信,支付宝小程序中的CI/CD,不要再让别人打断你的开发思路了!
【小程序】微信,支付宝小程序中的CI/CD,不要再让别人打断你的开发思路了!
本篇文章先说一下自动上传是如何实现的

gitee webHook配置

添加webhook

【小程序】微信,支付宝小程序中的CI/CD,不要再让别人打断你的开发思路了!

勾选PR

【小程序】微信,支付宝小程序中的CI/CD,不要再让别人打断你的开发思路了!

添加完成

【小程序】微信,支付宝小程序中的CI/CD,不要再让别人打断你的开发思路了!


完成如上步骤后发起PR和更新PR后,码云会发起一个post请求到我们的承接接口。

接口实现

注册之前码云上填写的路由来接收WebHook

router.post('/upload/:appKey', async ctx => {

// ...log

}

启动node服务,这时我们去刚刚添加完成的页面点一下测试按钮,接口就能接收到码云发来的请求啦~


既然第一步已经完成,那么我们梳理一下这个接口需要实现的内容:

  • 校验PR的目标分支和PR的状态
  • clone或者pull目标分支的代码至本地
  • 校验是否需要上传,version是否需要+1,是否为正式环境(与自己项目耦合的功能)
  • 叮叮通知开始上传
  • 上传
  • 叮叮通知上传成功
  • 结束

梳理完之后是不是非常的清晰,接下来让我们一步步来实现它

校验目标分支和PR状态

因为我们所有的PR目标分支均是master,并且需要提审的版本也是master,所以在接收到请求之后,需要判断一下目标分支是不是master并且PR的状态是不是合并完成。
WebHook推送数据的数据类型文档
PS:PR分为新建,更新,合并,关闭,每次状态更新都会发起一次请求,所以需要过滤不是合并的请求

router.post('/upload/:appKey', async ctx => {

const { body } = ctx.request

if (body.state === 'merged' && body.target_branch === "master") {

// ...

}

}

拉取代码

校验完之后就需要拉取代码,如果项目目录存在就去pull,不存在就去clone(偷个懒,确保你的目录是存在的,不然会报错)

if (fs.existsSync(xcxpath)) {

child_process.execSync('git pull', {

cwd: xcxPath

})

} else {

child_process.execSync(`git clone ${git地址}`, {

cwd: path.join(xcxPath, '..'))

})

}

自定义校验

接下来就需要去做一些与自己项目相关的上传前的校验,比如我们有些时候可能存在多个PR,不想每次合并后都上传一次,这时我们利用PR中的标签来判断是否需要上传,当我们选中aNotUpload标签时,这个PR将不会上传
【小程序】微信,支付宝小程序中的CI/CD,不要再让别人打断你的开发思路了!

let arr = body.pull_request.labels.filter(item => item.name === 'aNotUpload')

if( arr.length ) {

// ...存在,所以不上传

ctx.body = {

code: 200,

msg: '自主选择不上传',

success: true

}

return

}

然后我们也维护了一套自己的version用来区分每次的版本,但是每次都需要手动去+1,非常不合理。为了完成这个自动化,在合并PR之后(合并了所有commit)偷偷在master增加version并且push(暂时没有想到更合理的方法)

const parser = require("@babel/parser");

const generator = require("@babel/generator").default;

const traverse = require("@babel/traverse").default;

// 获取ast

function readConfig(root) {

const configFile = path.join(root, '/config/config.js')

const context = fs.readFileSync(configFile, "utf-8")

const ast = parser.parse(context)

return {

ast,

file: configFile

}

}

// version是否+1

function prodHooks({

root,

appKey

}) {

let {

ast,

file

} = readConfig(root)

let isVersionUp = false

// 是否上升了一个版本号

const diffStr = child_process.execSync(`git diff HEAD^ config/config.js`, {

cwd: '项目路径',

encoding: 'utf-8'

})

// 获取不同的version,大概得到['- version: "10.0.0"', '+ version: "10.0.1"']

let diffArr = diffStr.match(/(\+|-)(.*)version:[^\r\n]*[\r\n]/g)

if (diffStr && diffArr.length) {

// 提取数字

diffArr = diffArr.map(i => i.replace(/\D*/g, ''))

// +的version是否比-的version大,是的话就完成了version的提升

isVersionUp = diffArr[1] - diffArr[0] > 0

}

// 没有增加version,自动+1

if(!isVersionUp) {

traverse(ast, {

enter(p) {

if (p.isObjectProperty()) {

let name = p.node.key.name

if (name === 'version' || name === 'versionCode') {

let val = p.node.value.value

if (typeof val === 'string') {

val = versionUpdate(val)

} else {

val += 1

}

p.node.value.value = val

}

}

}

})

const {

code

} = generator(ast)

fs.writeFileSync(file, code, "utf-8")

child_process.execSync(`git add . && git commit -m 'version up' && git pull && git push`, {

cwd: '项目目录'

})

}

return true

}

/**

* 升级版本号

* @param {string} val '2.09.09' | '99.99.99'

* @return {string} '2.09.10' | '100.00.00'

*

*/

function versionUpdate(val) {

let num = [...(1 + Number(val.replace(/\D/g, '')) + '')]

for(let i=val.length-1; i>=0; i--){

if(val[i] === '.') {

num.splice(i - val.length + 1 , 0, '.')

}

}

return num.join('')

}

到这里我们完成了所有上传前的校验和自定义处理,接下来就到了最重要的通知和上传阶段啦~

钉钉群通知

平常上班主要使用钉钉,所以接入钉钉群机器人通知上传进度
PS:钉钉群机器人SDK
先创建一个钉钉群并设置自定义机器人获取accessToken和secret
【小程序】微信,支付宝小程序中的CI/CD,不要再让别人打断你的开发思路了!
【小程序】微信,支付宝小程序中的CI/CD,不要再让别人打断你的开发思路了!
【小程序】微信,支付宝小程序中的CI/CD,不要再让别人打断你的开发思路了!
点击完成后打开机器人
【小程序】微信,支付宝小程序中的CI/CD,不要再让别人打断你的开发思路了!
就可以得到accessToken和secret
然后利用sdk向钉钉群发送一个推送吧

const Robot = require('dingtalk-robot-sdk');

const robot = new Robot({

accessToken: 'xxxx',

secret: 'xxxx'

});

const text = new Robot.Text('走起~')

robot.send(text)

上传

支付宝和微信小程序利用sdk上传前的准备工作这边就不说啦,大家跟着官方文档去配置吧
PS:微信上传文档,支付宝上传文档
支付宝

alipaydev.setConfig({

toolId,

privateKey,

})

const uploadResult = await alipaydev.miniUpload({

appId: '支付宝appid',

clientType: 'alipay',

project: '项目地址',

experience: true // 设置为体验版

})

微信

const project = new ci.Project({

appid,

type: 'miniProgram',

projectPath,

privateKeyPath

})

const year = new Date().getFullYear() - 2000

let month = new Date().getMonth() + 1

const day = new Date().getDate()

// 根据年月日当版本号

const version = '2.5.' + year + (month < 10 ? '0' + month : month) + (day < 10 ? '0' + day : day);

// 上传

const previewResult = await ci.upload({

project,

version,

desc: body.title,

setting: {

es6: true,

minify: true,

autoPrefixWXSS: true,

minifyWXML: true,

minifyWXSS: true,

minifyJS: true

}

})

以上是 【小程序】微信,支付宝小程序中的CI/CD,不要再让别人打断你的开发思路了! 的全部内容, 来源链接: utcz.com/a/97843.html

回到顶部