1. 授权认证
  2. 获取用户个人信息
  3. 项目协同
  4. 代码托管
  5. 持续集成
  6. 制品仓库
  7. 测试管理
  8. 文档管理
  1. 项目协同
  2. 代码仓库
  3. DevOps 实践之旅
  4. 一分钟开始持续集成之旅
  5. 持续部署
  6. 制品库

基于 CI 实现微信小程序的持续构建

做为一个前端开发,在开发微信小程序的时候,我们应该都遇到过这样的场景:

我们双手正在在键盘上飞舞,像写诗一样认真的编写每一行代码,脑海里想着解耦合、设计模式、抽象和分层的时候。突然之间,

产品经理轻轻拍了拍了你肩膀,假装满怀歉意的跟你说:“我需要一个最新测试环境的体验二维码“

于是你端起了印着“和气生财”的马克杯,喝了口水,开始了一波操作

1. git stash
2. git checkout branch
3. npm install
4. npm build
5. 点击“预览”,生成二维码,发送给对方

搞定后,你活动了一下有些许酸疼的手指,切回分支恢复进度,脑海里努力得回忆着刚刚得思路。

这时,测试工程师突然又找你,他也想要一个测试环境的二维码,这时候你又看了看一眼你的马克杯,黯然神伤…

概括

本文将借助于 CODING 的持续集成,手把手带你实现一个微信小程序的持续集成环境,从构建、发布、通知实现自动化,帮你告别繁琐重复性的劳动。帮你解决上诉的烦恼。

整个工作流程如下

整个实现流程大致如下:

1,创建 CODING DevOps 项目

2,创建构建计划,配置微信小程序代码上传白名单

3,配置微信小程序代码上传私钥到环境变量中

4,配置企业微信的 webhook 地址到环境变量中

5,配置构建计划,分为 4 个步骤(检出、编译、上传新版本、发送通知)

下面我们来一步步实现它。

准备工具

  • CODING DevOps 项目
  • 微信小程序具有管理员权限的账号
  • 企业微信

创建 CODING DevOps 项目

登陆到 CODING 的工作台,在右上角选择 新增项目。随后选择 DevOps 项目创建即可。

设置小程序白名单

小程序代码上传需要配置 IP 的白名单,只有在指定的 IP 下才可以上传代码。
设置白名单分为两步:

1,我们来到 CODING DevOps 的项目中,新建一个构建计划,选择自定义构建过程
然后在构建详情选,选择 “基础信息”,在节点池中,复制选节点的公网出口

2,到微信小程序管理后台的 左侧菜单中选择 开发 -> 开发者设置 -> 小程序代码上传 -> 编辑 IP 白名单,将刚刚复制到的出口地址添加进去。

环境变量配置

持续集成过程中,我们总会将一些配置(如:账号密码/版本号等)信息以环境变量的形式注入到构建过程中。

CODING 持续集成支持多种环境变量使用形式,具体可查阅此文档

在本例中,我们需要设置两个环境变量

  • 微信小程序代码上传私钥

  • 企业微信机器人 webhook 地址

小程序代码上传私钥

微信小程序代码上传的私钥,可在微信管理后台:开发 -> 开发设置 -> 小程序代码上传 中获取。先保存到本地

然后我们来到 CODING DevOps 项目中的 项目设置 -> 开发者选项 -> 凭据管理 -> 新增凭据 -> 选择 SSH 私钥

打开我们之前在微信管理后台获取到的 ssh 私钥文件,复制里面的内容粘贴到凭据里面去保存。CODING 会对您的私钥进行加密保存,不会泄漏出去。

最后,回到我们刚刚创建的构建计划,在编辑模式中,选中顶部菜单的 “变量与缓存“。选择新建环境变量 -> coding 凭证,选择我们刚刚创建的 SSH 私钥。

企业微信群聊机器人 webhook

企业微信群聊机器人的 webhook 可以在群聊右键菜单中选择“新建群机器人”,在新建成功后,可以看到 webhook 地址,将它复制一下。
最后,回到我们刚刚创建的构建计划,在编辑模式中,选中顶部菜单的 “变量与缓存“。选择新建环境变量 -> 字符串类型,将刚刚复制的 webhook 地址粘贴进去即可。



配置构建流程

接下来我们来配置一下整个构建流程,在刚刚创建的构建计划,在编辑模式中,选中顶部菜单的 “流程编辑“ -> 选择 “文本编辑器”。

整个 Jenkinsfile 代码如下,

可以看到,主要分为检出、构建、上传版本、发送通知等 4 个阶段

主要都是调用一些脚本,下文中会对每个 stage 进行说明。

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('构建') {
        steps {
          echo '开始安装依赖'
          sh 'npm install'
          echo '开始构建...'
          sh 'npm run build'
          echo '构建完成'
        }
    }
    stage('上传新版本') {
        steps {
          withCredentials([sshUserPrivateKey(credentialsId: "${env.privatekey}",keyFileVariable: 'identity')]) {
            sh 'node upload.js -p ${identity}'
          }
        }
    }
    stage('发送新版本通知') {
        steps {
            sh 'node notification.js -u ${WECHAT_WEBHOOK}'
        }
    }
  }
}

构建阶段

可以看到就调用了两个命令:

npm install
npm run build

作为前端开发,我们都知道 npm 在执行 install 的时候因为网络原因是相当耗时的,而 CODING 持续集成提供的香港构建节点和构建缓存设置可以极大的提高 install 的速度。

具体你可以看到构建计划中的设置 -> 变量与缓存 菜单中找到。

在本例中,build 的规则比较简单:调用 gulp 运行了一个构建任务,将对应的 sass 文件处理成 wxss 文件,其他类型都是直接复制过去。

这个具体可根据自己的项目进行配置

本例的构建规则可查看源码仓库中的 gulpfile。

上传新版本

这里使用 miniprogram-ci 来实现代码的上传。

miniprogram-ci 是从微信开发者工具中抽离的关于小程序/小游戏项目代码的编译模块。开发者可不打开小程序开发者工具,独立使用 miniprogram-ci 进行小程序代码的上传、预览等操作。

此前我们将小程序上传代码的凭证加到环境变量中,这里我们使用 withCredentials 快速提取凭证,凭据具体的使用可以查看凭据使用

withCredentials([sshUserPrivateKey(credentialsId: "${env.privatekey}",keyFileVariable: 'identity')]) {
   sh 'node upload.js -p ${identity}'
}

提取到凭证后,调用了一个 upload.js 脚本。这里主要是利用 miniprogram-ci 进行代码的上传和预览二维码的生成,请看下方的代码。

const ci = require('miniprogram-ci')
const path = require('path');
const fs = require("fs");
const argv = require('minimist')(process.argv.slice(2));
const package = require('./package.json')
const appDirectory = fs.realpathSync(process.cwd());
const ProjectConfig = require('./dist/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: package.version,
            desc: package.versionDesc,
            setting: {
                ...ProjectConfig.setting
            },
            onProgressUpdate: console.log,
        })
        await ci.preview({
            project,
            version: package.version,
            desc: package.versionDesc,
            qrcodeFormat: "image",
            qrcodeOutputDest: previewPath,
            setting: {
                ...ProjectConfig.setting
            },
            onProgressUpdate: console.log,
        })
    } catch (e) {
        console.error(e);
        process.exit(1);
    }

})()

通知阶段

这里也很简单,直接发送一个请求,触发 webhook ,将预览二维码发送出去。

关于企业微信 API 的可查看这里企业微信文档

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 appDirectory = fs.realpathSync(process.cwd());

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


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);

    } catch(e) {
        console.error(e);
        process.exit(1);
    }
})()

当我们把代码上传,发布新版本之后,就会往企业微信群上发送一个预览二维码,通知群上的同事进行预览体验

到这里,就完成整个微信小程序自动化构建上传的全部流程啦,源码可在这里找到:源码地址

总结

更多扩展

  • 版本号和版本说明没有集中管理,目前是读取 package.json 文件里的 version 和 versionDesc,像团队里其他角色,像产品或者测试,想知道某个版本更新了什么内容就比较麻烦。这里可以试着使用 CODING 代码仓库的版本管理,通过 tag 来管理版本,同时配置通过 tag 来触发构建。

  • 通知只发送了二维码,没有发送版本号和版本说明,这里通过企业微信的 api,发送图文信息来解决,由于图文信息的 api 需要图片的网络地址,需要增加 cdn 的上传环节,为了不增加示例的复杂度,这里就没有实现。

上一篇构建基于 Tensorflow.js 的机器学习应用
最近更新
感谢反馈有用
感谢反馈没用

在阅读中是否遇到以下问题?

您希望我们如何改进?