背景和阐明:
  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:prod

配置和代码

针对问题1,配置的Jenkins

针对问题1,测试环境应用的Jenkinsfile

//Jenkinsfiledef 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

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

// Jenkinsfile.proddef 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插件