【小程序】小程序Jenkins部署实践

背景和说明:

  1. 代码是同一份,根据不同业务场景,打包出不同渠道的小程序,小程序之间的区别是功能的删减、底部菜单首页、业务接口传参带上不同的渠道号
  2. 该项目使用的是uniapp
  3. 本文章只涉及打包微信小程序

遇到的问题:

  1. 提测之后和每次修改bug,都需要打包给测试同事新包,而且不同渠道就要打不同的包,平均打一次包就要花费2min~3min,很浪费时间;打包过程占用本地机器的资源,导致电脑卡顿;打完包之后还要手动发包给测试,每个包还要重命名标识渠道。
  2. 每次提审小程序,都需要一次性打包多个渠道小程序,然后手动一个个小程序去上传,然后填写一模一样的提审信息,还要手动添加一些本渠道的标识信息,很容易出错。

问题分析:

问题1

  1. 其实可以通过写一个shell脚本,或者node脚本,实现打包、把目标文件夹变成zip包、重命名。
  2. 缺点是:①占用本地机器的资源,导致工作效率低下;②用脚本打包,需要填写参数,不方便且不直观。
  3. 更好的方案:使用Jenkins,且可以让测试自行打包和下载包。

问题2

  1. 其实可以用微信小程序cli来上传包,然后再用脚本来解决批量上传的问题。
  2. 缺点,除了问题1提到的缺点,还有:①cli的路径,在每个开发者的电脑上是不一致的,而且还要考虑是windows还是mac机器;②使用cli打包,第一次需要扫码,且还要考虑过期的问题,还要考虑个别开发者没有权限
  3. 更好的方案:使用miniprogram-ci + Jenkins,免登录且自动化

规划&效果展示

问题1,只出现在测试环境下;问题2,只出现在生产环境下。所以要部署两套Jenkins,而且对应的Jenkinsfile也区分开

针对问题搭建的Jenkins:test
【小程序】小程序Jenkins部署实践
【小程序】小程序Jenkins部署实践

针对问题搭建的Jenkins:prod
【小程序】小程序Jenkins部署实践
【小程序】小程序Jenkins部署实践

配置和代码

针对问题1,配置的Jenkins
【小程序】小程序Jenkins部署实践
针对问题1,测试环境使用的Jenkinsfile

//Jenkinsfile

def isInChannels(String channel) {

Boolean result = false;

String channels = "${params.CHANNELS}";

String[] arr = channels.split(',');

for (String item in arr) {

if (item == channel) {

result = true

}

}

return result;

}

pipeline {

agent any

parameters {

gitParameter branchFilter: 'origin/(.*)', defaultValue: 'master', name: 'BRANCH', type: 'PT_BRANCH'

}

stages {

stage('Checkout') {

steps {

echo ">>>>>>>> Checkout branch ${params.BRANCH}"

git branch: "${params.BRANCH}", url: 'http://1*************.git', credentialsId: '***************'

}

}

stage('Install') {

when {

expression {

return params.INSTALL

return isInChannels('malllive')

}

}

steps {

echo ">>>>>>>> Install ${params.INSTALL}..."

sh "cd ${WORKSPACE}"

sh "rm -rf node_modules/"

sh 'npm install'

}

}

stage('单店') {

when {

expression {

return isInChannels('mall')

}

}

steps {

echo ">>>>>>>>>> Cleaning...."

sh "cd ${WORKSPACE}"

sh "rm -rf dist/build/mall"

echo ">>>>>>>> build"

sh "npm run test:wx:mall:build" // 打包

sh "mv dist/build/mp-weixin dist/build/mall"

script {

currentBuild.description = currentBuild.description + "<a href='http://**********/job/*************/${BUILD_NUMBER}/execution/node/3/ws/dist/build/mall/*zip*/单店.zip'>下载单店包</a><br/>" // 提供下载包的链接,这个包已经重命名好了,而且是jenkins自带可以打包成zip包

}

}

}

stage('单店带直播') {

when {

expression {

return isInChannels('malllive')

}

}

steps {

echo ">>>>>>>>>> Cleaning...."

sh "cd ${WORKSPACE}"

sh "rm -rf dist/build/malllive"

echo ">>>>>>>> build"

sh "npm run test:wx:malllive:build"

sh "mv dist/build/mp-weixin dist/build/malllive"

script {

currentBuild.description = currentBuild.description + "<a href='http://**********/job/*************/${BUILD_NUMBER}/execution/node/3/ws/dist/build/malllive/*zip*/单店带直播.zip'>下载单店带直播包</a><br/>"

}

}

}

stage('品牌') {

when {

expression {

return isInChannels('brand')

}

}

steps {

echo ">>>>>>>>>> Cleaning...."

sh "cd ${WORKSPACE}"

sh "rm -rf dist/build/brand"

echo ">>>>>>>> build"

sh "npm run test:wx:brand:build"

sh "mv dist/build/mp-weixin dist/build/brand"

script {

currentBuild.description = currentBuild.description + "<a href='http://**********/job/*************/${BUILD_NUMBER}/execution/node/3/ws/dist/build/brand/*zip*/品牌.zip'>下载品牌包</a><br/>"

}

}

}

stage('品牌不带预订') {

when {

expression {

return isInChannels('brandnobook')

}

}

steps {

echo ">>>>>>>>>> Cleaning...."

sh "cd ${WORKSPACE}"

sh "rm -rf dist/build/brandnobook"

echo ">>>>>>>> build"

sh "npm run test:wx:brandnobook:build"

sh "mv dist/build/mp-weixin dist/build/brandnobook"

script {

currentBuild.description = currentBuild.description + "<a href='http://**********/job/*************/${BUILD_NUMBER}/execution/node/3/ws/dist/build/brandnobook/*zip*/品牌不带预订.zip'>下载品牌不带预订包</a><br/>"

}

}

}

stage('尊享会') {

when {

expression {

return isInChannels('group')

}

}

steps {

echo ">>>>>>>>>> Cleaning...."

sh "cd ${WORKSPACE}"

sh "rm -rf dist/build/group"

echo ">>>>>>>> build"

sh "npm run test:wx:group:build"

sh "mv dist/build/mp-weixin dist/build/group"

script {

currentBuild.description = currentBuild.description + "<a href='http://**********/job/*************/${BUILD_NUMBER}/execution/node/3/ws/dist/build/group/*zip*/尊享会.zip'>下载尊享会包</a><br/>"

}

}

}

stage('预订') {

when {

expression {

return isInChannels('bookmall')

}

}

steps {

echo ">>>>>>>>>> Cleaning...."

sh "cd ${WORKSPACE}"

sh "rm -rf dist/build/bookmall"

echo ">>>>>>>> build"

sh "npm run test:wx:bookmall:build"

sh "mv dist/build/mp-weixin dist/build/bookmall"

script {

currentBuild.description = currentBuild.description + "<a href='http://**********/job/*************/${BUILD_NUMBER}/execution/node/3/ws/dist/build/bookmall/*zip*/预订.zip'>下载预订包</a><br/>"

}

}

}

stage('预订铂涛') {

when {

expression {

return isInChannels('bookmallbtzh')

}

}

steps {

echo ">>>>>>>>>> Cleaning...."

sh "cd ${WORKSPACE}"

sh "rm -rf dist/build/bookmallbtzh"

echo ">>>>>>>> build"

sh "npm run test:wx:bookmall:build:bt"

sh "mv dist/build/mp-weixin dist/build/bookmallbtzh"

script {

currentBuild.description = currentBuild.description + "<a href='http://**********/job/*************/${BUILD_NUMBER}/execution/node/3/ws/dist/build/bookmallbtzh/*zip*/预订铂涛.zip'>下载预订铂涛包</a><br/>"

}

}

}

}

}

针对问题2,配置的Jenkins
【小程序】小程序Jenkins部署实践

针对问题2,生产环境使用的Jenkinsfile,我这里的文件名叫做Jenkinsfile.prod,跟Jenkins配置的Script Path需要一致

// Jenkinsfile.prod

def isInChannels(String channel) {

Boolean result = false;

String channels = "${params.CHANNELS}";

String[] arr = channels.split(',');

for (String item in arr) {

if (item == channel) {

result = true

}

}

return result;

}

pipeline {

agent any

parameters {

gitParameter branchFilter: 'origin/(.*)', defaultValue: 'master', name: 'BRANCH', type: 'PT_BRANCH'

}

stages {

stage('Checkout') {

steps {

echo ">>>>>>>> Checkout branch ${params.BRANCH}"

git branch: "${params.BRANCH}", url: 'http://******************.git', credentialsId: '******************'

}

}

stage('Install') {

when {

expression {

return params.INSTALL

}

}

steps {

echo ">>>>>>>> Install ${params.INSTALL}..."

sh "cd ${WORKSPACE}"

sh "rm -rf node_modules/"

sh 'npm install'

}

}

stage('单店') {

when {

expression {

return isInChannels('mall')

}

}

steps {

echo ">>>>>>>>>> Cleaning...."

sh "cd ${WORKSPACE}"

sh "rm -rf dist/build/mall"

echo ">>>>>>>> build"

sh "npm run build:wx:mall" // 打包点单的命令,下面的同理,打包对应的渠道包的命令

sh "mv dist/build/mp-weixin dist/build/mall"

sh "node build/upload/index.js -v ${params.VER} -d (生产)(单店)${params.DESC} -i wx*************9560 -p dist/build/mall"

sh "wget https://************************" // 如果没有接入微信第三方平台,可忽略。因为我们接入了微信第三方平台,上传代码之后需要把草稿添加到模板,我们这里做了一个接口自动添加草稿到模板。

}

}

stage('单店带直播') {

when {

expression {

return isInChannels('malllive')

}

}

steps {

echo ">>>>>>>>>> Cleaning...."

sh "cd ${WORKSPACE}"

sh "rm -rf dist/build/malllive"

echo ">>>>>>>> build"

sh "npm run build:wx:malllive"

sh "mv dist/build/mp-weixin dist/build/malllive"

sh "node build/upload/index.js -v ${params.VER} -d (生产)(单店带直播)${params.DESC} -i wx*************9560 -p dist/build/malllive"

sh "wget https://*************"

}

}

stage('品牌') {

when {

expression {

return isInChannels('brand')

}

}

steps {

echo ">>>>>>>>>> Cleaning...."

sh "cd ${WORKSPACE}"

sh "rm -rf dist/build/brand"

echo ">>>>>>>> build"

sh "npm run build:wx:brand"

sh "mv dist/build/mp-weixin dist/build/brand"

sh "node build/upload/index.js -v ${params.VER} -d (生产)(品牌)${params.DESC} -i wx*************9560 -p dist/build/brand"

sh "wget https://*************"

}

}

stage('品牌不带预订') {

when {

expression {

return isInChannels('brandnobook')

}

}

steps {

echo ">>>>>>>>>> Cleaning...."

sh "cd ${WORKSPACE}"

sh "rm -rf dist/build/brandnobook"

echo ">>>>>>>> build"

sh "npm run build:wx:brandnobook"

sh "mv dist/build/mp-weixin dist/build/brandnobook"

sh "node build/upload/index.js -v ${params.VER} -d (生产)(品牌不带预订)${params.DESC} -i wx*************9560 -p dist/build/brandnobook"

sh "wget https://*************"

}

}

stage('尊享会') {

when {

expression {

return isInChannels('group')

}

}

steps {

echo ">>>>>>>>>> Cleaning...."

sh "cd ${WORKSPACE}"

sh "rm -rf dist/build/group"

echo ">>>>>>>> build"

sh "npm run build:wx:group"

sh "mv dist/build/mp-weixin dist/build/group"

sh "node build/upload/index.js -v ${params.VER} -d (生产)(尊享会)${params.DESC} -i wx*************9560 -p dist/build/group"

sh "wget https://*************"

}

}

stage('预订') {

when {

expression {

return isInChannels('bookmall')

}

}

steps {

echo ">>>>>>>>>> Cleaning...."

sh "cd ${WORKSPACE}"

sh "rm -rf dist/build/bookmall"

echo ">>>>>>>> build"

sh "npm run test:wx:bookmall:build"

sh "mv dist/build/mp-weixin dist/build/bookmall"

sh "node build/upload/index.js -v ${params.VER} -d (生产)(预订)${params.DESC} -i wx*************93a0 -p dist/build/bookmall"

}

}

stage('预订铂涛') {

when {

expression {

return isInChannels('bookmallbtzh')

}

}

steps {

echo ">>>>>>>>>> Cleaning...."

sh "cd ${WORKSPACE}"

sh "rm -rf dist/build/bookmallbtzh"

echo ">>>>>>>> build"

sh "npm run test:wx:bookmall:build:bt"

sh "mv dist/build/mp-weixin dist/build/bookmallbtzh"

sh "node build/upload/index.js -v ${params.VER} -d (生产)(预订铂涛)${params.DESC} -i wx*************7974 -p dist/build/bookmallbtzh"

}

}

}

}

使用miniprogram-ci上传的脚本

// 使用miniprogram-ci上传

const program = require('commander');

const ci = require('miniprogram-ci');

program

.version('1.0.0')

.option('-i, --appid [APPID]', '模板小程序appid')

.option('-p, --projectpath [PROJECTPATH]', '项目路径')

.option('-v, --ver [VER]', '小程序版本')

.option('-d, --desc [DESC]', '版本描述')

.parse(process.argv);

;(async () => {

const project = new ci.Project({

appid: `${program.appid}`,

type: 'miniProgram',

projectPath: program.projectpath,

privateKeyPath: `build/upload/privatekeys/private.${program.appid}.key`,

ignores: ['node_modules/**/*'],

})

const uploadResult = await ci.upload({

project,

version: program.ver,

desc: program.desc,

setting: {

es6: true,

es7: true,

autoPrefixWXSS: true,

minify: true

}

})

console.log(uploadResult)

})()

补充说明

  1. Jenkinsfile,是用groovy语法,如果想添加一些函数之类的,可以查一下对应的语法,我用到的isInChannels方法就是用的groovy语法
  2. Jenkins默认不支持多选,需要安装Extend Choice Parameter插件

以上是 【小程序】小程序Jenkins部署实践 的全部内容, 来源链接: utcz.com/a/103742.html

回到顶部