微信小程序CI实践(Remax版)

1,486 阅读4分钟

小试Remax

Remax是一个多端小程序构建框架

我们先安装Remax并新建一个项目。在你喜欢的目录下执行操作

npx create-remax-app ci-demo

cd my-app && npm install

这样我们就建好一个Remax的Demo了。

由于这次我们实践只涉及CI部分所以我们不涉及业务的编码。

image.png 接着我们dev一个微信小程序,我们继续执行命令。

remax build -t wechat -w

-t 为target目标平台 -w 为是否是watch模式

在小程序中把生成的dist放到小程序目录中

image.png

跑起来就可以看到熟悉的Remax启动界面。

image.png

Remax CI配置

在项目目录下创建ci文件夹,并开始加入notification.js和upload.js文件

image.png

微信小程序CI需要在你的package.json依赖中新增三个包。分别是

md5-file:生成md5文件名的预览二维码

minimist: 解析上传的参数

miniprogram-ci:微信小程序CI工具库

"dependencies": {
    "md5-file": "^5.0.0",
    "minimist": "^1.2.5",
  },
"devDependencies": {
    "miniprogram-ci": "^1.2.3"
  }

注意这里的预览二维码是开发版有有效期和自动刷新的体验版不同。

notifcation.js(用于在企业微信或者钉钉中发送相应版本构建后的开发二维码)

const md5File = require('md5-file');
const axios = require('axios');
const path = require('path');
const argv = require('minimist')(process.argv.slice(2));
const fs = require('fs');
const package_info = require('../package.json')

const appDirectory = fs.realpathSync(process.cwd());

const previewPath = path.resolve(appDirectory, './preview.jpg');

function sendVersionInfo() {
    let fixList = ''
    package_info.upadte_info.fix.map((item, index) => {
        if (item) {
            fixList += `${index + 1}.${item}\n`
        }
    })
    
    let featList = ''
    package_info.upadte_info.feat.map((item, index) => {
        if (item) {
            featList += `${index + 1}.${item}\n`
        }
    })

    let refactorList = ''
    package_info.upadte_info.refactor.map((item, index) => {
        if (item) {
            refactorList += `${index + 1}.${item}\n`
        }
    })

    return axios({
        headers: {'Content-Type': 'application/json'},
        method: 'post',
        url: argv.u,
        data: {
            msgtype: 'text',
            text: {
                content: `(↑↑↑)\n当前版本:v${package_info.version}\n修复:\n${fixList}\n新增:\n${featList}\n重构:\n${refactorList}`
            },
        },
    });
}

function sendQrCode(imageBase64, hash) {
    return axios({
        headers: {'Content-Type': 'application/json'},
        method: 'post',
        url: argv.u,
        data: {
            msgtype: 'image',
            image: {
                base64: imageBase64,
                md5: hash,
            },
        },
    });
}

(async () => {
    try {
        const imageData = fs.readFileSync(previewPath);
        const hash = md5File.sync(previewPath);
        const imageBase64 = imageData.toString('base64');
        await sendQrCode(imageBase64, hash);
        await sendVersionInfo()
    } catch (e) {
        console.error(e);
        process.exit(1);
    }
})();

upload.js

const ci = require('miniprogram-ci')
const path = require('path');
const fs = require("fs");
const argv = require('minimist')(process.argv.slice(2));
const packageInfo = require('../package.json')
const appDirectory = fs.realpathSync(process.cwd());
const projectConfig = require('../project.config.json');
const previewPath = path.resolve(appDirectory, './preview.jpg');


(async () => {
    try {
        const project = new ci.Project({
            appid: projectConfig.appid,
            type: "miniProgram",
            projectPath: path.resolve(appDirectory, './dist'),
            privateKeyPath: argv.p,
            ignores: ["node_modules/**/*"],
        })
        await ci.upload({
            project,
            version: packageInfo.version,
            desc: packageInfo.description,
            setting: {
                ...projectConfig
            },
            onProgressUpdate: console.log,
        })
        await ci.preview({
            project,
            version: packageInfo.version,
            desc: packageInfo.description,
            qrcodeFormat: "image",
            qrcodeOutputDest: previewPath,
            setting: {
                ...projectConfig
            },
            onProgressUpdate: console.log,
        })
    } catch (e) {
        console.error(e);
        process.exit(1);
    }

})()

微信公众号配置

先到微信公众号后台登录你的小程序关联账号。

再在"微信公众平台-开发-开发设置"中设置小程序的上传密钥

小程序代码上传密钥 微信官方文档

企业微信配置

现在我们可以配置一个企业微信的技术群机器人(你的技术群->右键"添加机器人")。

然后就可以获取到一个你们群内的webhook链接,我们保存这里链接。一会需要放到Coding环境变量中。

image.png

Coding持续集成

登录Coding在持续集成中新建一个计划 image.png

贴入以下jenkins代码

pipeline {
  agent any
  stages {
    stage('检出') {
        steps {
            checkout([
            $class: 'GitSCM',
            branches: [[name: env.GIT_BUILD_REF]],
            userRemoteConfigs: [[
                url: env.GIT_REPO_URL,
                credentialsId: env.CREDENTIALS_ID
            ]]])
        }
    }
    stage('构建/lint检查') {
        steps {
          echo '开始安装依赖'
          sh 'yarn'
          // echo '开始lint检查'
          // sh 'yarn lint'
          echo '开始构建...'
          sh 'yarn run build'
          echo '构建完成'
        }
    }
    stage('上传新版本') {
        steps {
          withCredentials([sshUserPrivateKey(credentialsId: "${env.privatekey}",keyFileVariable: 'identity')]) {
            sh 'node ci/upload.js -p ${identity}'
          }
        }
    }
    stage('发送新版本通知') {
        steps {
            sh 'node ci/notification.js -u ${ROBOT_HOOKS}'
        }
    }
  }
}

在你的CI jenkins配置中,运用这下面的文件。把你的上传密钥和Webhook设置在CI集成的环境变量。 image.png

本次我们定义为privatekey和ROBOT_HOOKS。(可以改为任何你喜欢的变量,记得也在修改相应的环境变量)

上传密钥是一个cert的文件,你可以用vs code打开后再把相应的字符串复制到环境变量中

我们可以新建一个Coding凭据再关联到相应的CI计划

image.png

identity: 上传密钥

ROBOT_HOOKS: 企业微信的Webhook链接.

CodingRemax环境变量合并

在Remax中,我们可以使用REMAX_APP_前缀的变量作为环境变量带入Remax开发中。

实际开发中,都会分为开发服、测试服和正式服可以通过配置不同的build命令执行不同目标服务器构建。

可以约定一个REMAX_APP_BASE_URL作为环境变量,在Reamx build的时候执行。

这样可以修改一下需要用到接口的地方修改一下为

const url =  process.env.REMAX_APP_BASE_URL

这样可以做到我们不管发什么版本,都会通过对应的开发分支来构建。 而不至于频繁的修改url而导致线上的发版错误。

我们通过在Coding上的不同分支,进行不同的构建,因此我们会有dev分支CI构建的时候执行测试服的构建,master主分支构建的时候构建到正式服环境。

总结

通过以上的一波操作,我们就可以用Coding CI执行我们的小程序构建啦~

并且构建后版本更新信息和预览二维码都可以同步的发到技术群里。

可以让有开发权限的同事们一起测试提问题。通过测试后,就可以修改为体验版再进行全部测试。

最后合并到正式服提审,执行发版操作。