第一章 本周导学


1-1 本周整体内容介绍和学习方法

  • 云构建原理、架构和实现
  • WebSocket入门到实战
  • Redis入门实战

第二章 云架构模块架构设计


2-1 详细分析为什么需要设计云构建系统

为什么需要云构建

  • 减少发布过程中的重复劳动
    • 打包构建
    • 上传静态资源服务器
    • 上传CDN
  • 避免不同环境造成的差异
  • 提升构建性能
  • 对构建过程进行统一管控
    • 发布前代码统一规则检查
    • 封网日统一发布卡口

2-2 云构建系统架构设计

点击查看【processon】

第三章 WebSocket 快速入门


3-1 WebSocket基本概念及同HTTP协议对比

WebSocket概念

  • HTTP:请求响应的单向。
  • WebSocket:只需发起一次请求,双向发起请求,双向接收响应。常用为聊天工具、云构建请求。
  • 客户端开发WebSocket与浏览器开发WebSocket是不同的。
  • 如何通过NodeJs搭建一个WebSocket服务。

相关基本概念:https://www.runoob.com/html/html5-websocket.html

3-2 egg集成WebSocket服务

基础介绍

基础教程:https://eggjs.org/zh-cn/tutorials/socketio.html demo仓库:https://github.com/eggjs/egg-socket.io/tree/master/example

代码在lesson01分支基础上继续开发:cloudscope-cli-server/leeson01 在lesson01分支基础上,新建分支 lesson30,本周最终代码在lesson30分支上。

WebSocket服务开发流程

  1. 安装依赖
  • cnpm i -S egg-socket.io
  1. 更新配置文件
  1. // config.default.js
  2. config.io = {
  3. namespace: {
  4. '/': {
  5. connectionMiddleware: ['auth'],
  6. packetMiddleware: ['filter'],
  7. },
  8. '/chat': {
  9. connectionMiddleware: ['auth'],
  10. packetMiddleware: [],
  11. },
  12. },
  13. };
  14. // plugin.js
  15. exports.io = {
  16. enable: true,
  17. package: 'egg-socket.io',
  18. };
  1. 修改路由配置
  1. // router.js
  2. // app.io.of('/')
  3. app.io.route('chat', app.io.controller.chat.index);
  4. // app.io.of('/chat')
  5. app.io.of('/chat').route('chat', app.io.controller.chat.index);
  1. 开发middleware
  1. // app/io/middleware/auth.js
  2. 'use strict';
  3. module.exports = () => {
  4. return async (ctx, next) => {
  5. const say = await ctx.service.user.say();
  6. ctx.socket.emit('res', 'auth!' + say);
  7. await next();
  8. console.log('disconnect!');
  9. };
  10. };
  11. //app/io/middleware/filter.js
  12. 'use strict';
  13. module.exports = () => {
  14. return async (ctx, next) => {
  15. console.log(ctx.packet);
  16. const say = await ctx.service.user.say();
  17. ctx.socket.emit('res', 'packet!' + say);
  18. await next();
  19. console.log('packet response!');
  20. };
  21. };
  1. 开发controller
  1. // app/io/controller/chat.js
  2. 'use strict';
  3. module.exports = app => {
  4. class Controller extends app.Controller {
  5. async index() {
  6. const message = this.ctx.args[0];
  7. console.log('chat :', message + ' : ' + process.pid);
  8. const say = await this.ctx.service.user.say();
  9. this.ctx.socket.emit('res', say);
  10. }
  11. }
  12. return Controller;
  13. };

3-3 WebSocket客户端开发

代码分支在 cloudscope-cli/lesson30上。

  • lerna create cloudbuild models/
  • cd models/cloudbuild
  • npm i -S socket.io-client
  • cloudbuild/lib/index.js
  1. 'use strict';
  2. // or http://127.0.0.1:7001/chat
  3. const socket = require('socket.io-client')('http://127.0.0.1:7001');
  4. socket.on('connect', () => {
  5. console.log('connect!');
  6. socket.emit('chat', 'hello world!');
  7. });
  8. socket.on('res', msg => {
  9. console.log('res from server: %s!', msg);
  10. });

3-4 WebSocket客户端与服务端交互流程分析

以日志的打出分析流程
image.png
image.png

  • 首先服务端(cloudscope-cli-server)启动服务:npm run dev
  • 客户端启动服务:node models/cloudbuild/lin/index.js
  • 客户端启动后:
    • socket on 连接成功,监控connect事件:打印出日志 connect!
    • 接着客户端emit chat事件:socket.emit(‘chat’, ‘hello world!’);
  • 服务端接收到chat事件后
    • 首先会现在服务端config.default.js中找到 / 的 connectMiddleWare的 auth.js去执行
      • auth.js中触发res事件
      • 客户端监听res事件,打印日志:res from server:auth! Hello Man!!
    • 接着服务端在config.default.js中 找到 / 的packetMiddleWare 的 filter.js去执行
      • 服务端打印 ctx.packet日志:[‘chat’,’hello world!’]
      • filter.js触发res事件
      • 客户端监听res事件,打印日志:res from server:packet! Hello Man!!
    • 服务端通过route匹配到 chat,于是去Controller中找 chat.js
      • 服务端打印日志:chat:hello world! : 10826
      • 接着服务端调用service服务,拿到值,触发 res事件
      • 客户端监听到res事件,打印日志:res from server:Hello Man!!
    • 服务端等待 next执行完毕后,最后在 filter.js中,打印出:packet response!

第四章 Redis 快速入门


4-1 redis基本概念+安装方法+基本命令

  • 该项目应用redis是要:存储任务信息
  • redis安装
  • 常用命令redis-cli[进入终端服务]和redis-server[启动redis服务]

4-2 阿里云redis服务配置和远程连接方法讲解

我这里实在腾讯云领了一个月的redis免费试用版本,下面记录为课程的讲解,腾讯云相关redis见读书笔记。

  • 购买完数据库后,第一个设置是白名单设置,0.0.0.0/0 如果不设置,会出现远程无法连接的问题
  • 创建账号:使用默认账号或创建账号连接
  • 连接成功后 AUTH

4-3 egg集成redis方法讲解

redis为使用本地

  • 首先在npm官网上查看 egg-redis这个插件
  • 在server安装:npm i egg-redis —save
  • 根据npm官网上关于egg-redis的代码讲解,分别在plugin.js和config.default.js中添加相关代码。
  • 添加一个新路由:/redis/test,并在project的controller中测试
  • 添加 await app.redis.get(key)获取key值
  1. async getRedis(){
  2. const { ctx, app } = this;
  3. const num = await app.redis.get('number')
  4. console.log(num)
  5. ctx.body = 'hello redis'
  6. }
  7. //config.defualt.js
  8. config.redis = {
  9. client: {
  10. port: REDIS_PORT,
  11. host: REDIS_HOST,
  12. password:REDIS_PWD,
  13. db: 0,
  14. },
  15. //plugin.js
  16. exports.redis = {
  17. enable: true,
  18. package: 'egg-redis',
  19. };

第五章 云构建初始化流程开发


5-1 CloudBuild类开发

根据第二章 架构图,本节主要代码为 CloudBuild类的创建与引用,最终传入git对象

3-3节已经创建了cloudbuild,修改这里的代码为

  1. 'use strict';
  2. class CloudBuild {
  3. constructor(git, props){
  4. console.log('cloudbuild',git)
  5. }
  6. // or http://127.0.0.1:7001/chat
  7. // const socket = require('socket.io-client')('http://127.0.0.1:7001');
  8. // socket.on('connect', () => {
  9. // console.log('connect!');
  10. // socket.emit('chat', 'hello world!');
  11. // });
  12. // socket.on('res', msg => {
  13. // console.log('res from server: %s!', msg);
  14. // });
  15. }
  16. module.exports = CloudBuild

在modes/git下引入@cloudscope-cli/cloudbuild,并新建publish方法

  1. async publish(){
  2. await this.preparePublish()
  3. const buildCmd = ''
  4. const cloudBuild = new CloudBuild(this,{
  5. buildCmd
  6. })
  7. }
  8. async preparePublish(){
  9. console.log('preparePublish')
  10. }

在commands/publish/lib/index.js 文件中,接着上一周的 自动化提交代码,接着调用 git.publsih方法。

  • 这样从 commands/publish/lib/index.js中调用 git.publish()方法
  • 在 models/git/lib/index.js中开发publish方法,publish中会生成一个cloudbuild实例
  • 这个cloudbild实例为我们在models下新建的一个包,这样本节就形成了一个闭环。
  • 下节开始就是cloudbuild实例的开发,以及publish流程。

5-2 生成构建命令+构建命令检查开发

本节主要内容是,用于定制build命令,通过 —buildCmd参数,如果用户传入build命令,那么使用传入的build命令打包,如果不是则传入默认的打包命令。

  1. 首先在 core/cli/lib/index.js中传入 —buildCmd参数
  1. program
  2. .command('publish')
  3. .option('--refreshServer','强制更新远程Git仓库类型和token')
  4. .option('--refreshOwner','强制更新远程Git仓库用户类型')
  5. .option('--buildCmd <buildCmd>','构建命令')
  6. .action(exec)
  1. 然后在commands/publish/lib/index.js中接收这个参数
  1. class PublishCommand extends Command {
  2. init(){
  3. // 处理参数
  4. log.verbose('publish init',this._argv)
  5. this.options = {
  6. refreshServer:this._argv[0].refreshServer,
  7. refreshOwner:this._argv[0].refreshOwner,
  8. buildCmd:this._argv[0].buildCmd
  9. }
  10. }
  11. …………
  12. }
  1. 此时Git类接收并赋值该参数,然后在上节我们写的 [models/git/lib/index.js] publishPrepare中见检查这个命令
  1. async preparePublish(){
  2. if(this.buildCmd){
  3. const buildCmdArray = this.buildCmd.split(' ')
  4. if(!Object.is(buildCmdArray[0],'npm') && !Object.is(buildCmdArray[0],'cnpm')){
  5. throw new Error('Build命令非法,必须使用npm或cnpm!')
  6. }
  7. }else{
  8. this.buildCmd = 'npm run build'
  9. }
  10. console.log(this.buildCmd)
  11. }
  • 最后测试一下:

终端命令: cloudscope-cli publish —targetPath /Users/liumingzhou/Documents/imoocCourse/Web前端架构师/cloudscope-cli/commands/publish —buildCmd ‘anpm run build:prod’ 抛出异常:Build命令非法,必须使用npm或cnpm


5-3 通过CloudBuild创建WebSocket连接

我们在第三章的学习当中已经大略的知道了 前后端如何建立起socket连接,本节就是对服务端代码修改以及客户端代码开发-传递git.repo参数到服务端。

  • 服务端
    • 将与service有关的代码先删掉
    • 将routes.js中与chat相关的修改为 build:app.io.route(‘build’, app.io.controller.build.index);
    • 服务端学习的核心代码为:const query = socket.handshake.query
  1. //app/controller/io/controller/build.js
  2. 'use strict';
  3. module.exports = app => {
  4. class Controller extends app.Controller {
  5. async index() {
  6. console.log('Controller build!')
  7. }
  8. }
  9. return Controller;
  10. };
  11. //app/controller/io/middleware/auth.js
  12. 'use strict';
  13. module.exports = () => {
  14. return async (ctx, next) => {
  15. const {socket,logger} = ctx
  16. const query = socket.handshake.query
  17. logger.info(query)
  18. console.log('connect!')
  19. await next();
  20. console.log('disconnect!');
  21. };
  22. };
  • 客户端
    • Cloudbuild实例的init方法传入了一个参数:git.remote
  1. // models/cloudbuild/lib/index.js
  2. 'use strict';
  3. const io = require('socket.io-client');
  4. const TIME_OUT = 5* 60
  5. const WS_SERVER = 'http://liugezhou.com:7001'
  6. class CloudBuild {
  7. constructor(git, options){
  8. this.git = git
  9. this.buildCmd = options.buildCmd
  10. this.timeout = TIME_OUT
  11. }
  12. init(){
  13. const socket = io(WS_SERVER,{
  14. query:{
  15. repo:this.git.remote
  16. }
  17. })
  18. socket.on('connect', () => {
  19. console.log('connect!');
  20. // socket.emit('chat', 'hello world!');
  21. });
  22. }
  23. }

最后测试一下:

  • 最后测试一下,将服务端启动,在客户端执行命令:

终端命令: cloudscope-cli publish —targetPath /Users/liumingzhou/Documents/imoocCourse/Web前端架构师/cloudscope-cli/commands/publish —buildCmd ‘npm run build:prod’

  • 在客户端与服务端分别打印出日志,测试正确

5-4 WebSocket超时自动断开连接逻辑开发

本节比较简单,是解决连接不上服务端的问题—连接超时,抛出异常,部分代码如下:

  1. const CONNET_TIME_OUT = 5*1000
  2. class CloudBuild {
  3. constructor(git, options){
  4. this.git = git
  5. this.buildCmd = options.buildCmd
  6. this.timeout = TIME_OUT
  7. }
  8. doTtimeout(fn,timeout){
  9. this.timer && clearTimeout(this.timer)
  10. log.info('设置任务超时时间:',`${timeout/1000}秒`)
  11. this.timer = setTimeout(fn,timeout);
  12. }
  13. init(){
  14. const socket = io(WS_SERVER,{
  15. query:{
  16. repo:this.git.remote
  17. }
  18. })
  19. const disconnect = ()=>{
  20. clearTimeout(this.timer)
  21. socket.disconnect()
  22. socket.close()
  23. }
  24. this.doTtimeout(()=>{
  25. log.error('云构建服务连接超时,自动终止')
  26. disconnect()
  27. }, CONNET_TIME_OUT);
  28. }
  29. }

5-5 WebSocket客户端和服务端通信优化

在整个websocket连接成功之后,是可以发送一些标准化日志的。

  • 友好实现socket连接后的标准化日志,服务端改造
    • 第一个改造点,cloudscope-cli-server中auth.js添加try catch异常捕获
    • 第二个改造点:新建app/extend/helper.js,统一的返回格式
  1. // app/extend/helper.js
  2. 'use strict';
  3. module.exports = {
  4. parseMsg(action,payload={},metadata={}){
  5. const meta = Object.assign({},{
  6. timestamp:Date.now()
  7. },metadata);
  8. return {
  9. meta,
  10. data:{
  11. action,
  12. payload
  13. }
  14. }
  15. }
  16. }
  17. // app/controller/io/middleware/auth.js
  18. const {socket,logger,helper} = ctx
  19. socket.emit(id,helper.parseMsg('connect',{
  20. type:'connect',
  21. message:'云构建服务连接成功'
  22. }))

客户端

  1. const get =require('lodash/get')
  2. function parseMsg(msg){
  3. const action = get(msg,'data.action')
  4. const message = get(msg,'data.payload.message')
  5. return {
  6. action,
  7. message
  8. }
  9. }
  10. socket.on('connect', () => {
  11. clearTimeout(this.timer)
  12. const {id} = socket
  13. socket.on(id,msg=>{
  14. const parsedMsg = parseMsg(msg)
  15. log.success(parsedMsg.action,parsedMsg.message,`任务ID${id}`)
  16. })
  17. });
  18. socket.on('disconnect',()=>{
  19. log.success('disconnect','云构建任务断开')
  20. disconnect();
  21. })
  22. socket.on('error',(err)=>{
  23. log.error('error','云构建错误',err)
  24. disconnect()
  25. })

5-6 云构建任务写入Redis

本节主要内容就是将云构建任务写入到redis中去【服务端】,核心代码如下:

  1. // app/controller/io/middleware/auth.js
  2. const REDIS_PREFIX = 'cloudbuild'
  3. const {app} = ctx
  4. const {redis} = app
  5. // 判断redis任务是否存在
  6. let hashTask = await redis.get(`${REDIS_PREFIX}:${id}`)
  7. if(!hashTask){
  8. await redis.set(`${REDIS_PREFIX}:${id}`,JSON.stringify(query))
  9. }
  10. hashTask = await redis.get(`${REDIS_PREFIX}:${id}`)
  11. logger.info(hashTask)

5-7 创建云构建任务功能开发

客户端添加build方法

  1. // models/cloudbuild/lib/index.js
  2. build(){
  3. return new Promise((resolve,reject)=>{
  4. this.socket.emit('build')
  5. this.socket.on("build",msg=>{
  6. const parsedMsg = parseMsg(msg)
  7. log.success(parsedMsg.action,parsedMsg.message)
  8. })
  9. this.socket.on('building',msg=>{
  10. const parsedMsg = parseMsg(msg)
  11. log.success(parsedMsg.action,parsedMsg.message)
  12. })
  13. //commands/publish/lib/index.js
  14. //publish方法中
  15. await cloudBuild.init()
  16. await cloudBuild.build()

在服务端,我们在已经建好的 app/controller/io/controller/build.js中

  1. 'use strict';
  2. const REDIS_PREFIX = 'cloudbuild'
  3. const CloudBuildTask = require('../../models/CloudBuildTask')
  4. async function createCloudBuildTask(ctx,app){
  5. const { socket,helper } = ctx
  6. const { redis } = app
  7. const client = socket.id
  8. const redisKey = `${REDIS_PREFIX}:${client}`
  9. const redisTask = await redis.get(redisKey)
  10. const task = JSON.parse(redisTask)
  11. socket.emit('build',helper.parseMsg('create task',{
  12. message:'创建云构建任务'
  13. }))
  14. return new CloudBuildTask({
  15. repo:task.repo,
  16. name:task.name,
  17. version:task.version,
  18. branch:task.branch,
  19. buildCmd:task.buildCmd
  20. })
  21. }
  22. module.exports = app => {
  23. class Controller extends app.Controller {
  24. async index() {
  25. //创建云构建任务
  26. const {ctx,app} = this
  27. const cloudBuildTask = await createCloudBuildTask(ctx,app)
  28. }
  29. }
  30. return Controller;
  31. };
  32. // app/models/CloudBuildTask.js
  33. 'use strict';
  34. class CloudBuildTask {
  35. constructor(options){
  36. console.log(options)
  37. }
  38. }
  39. module.exports = CloudBuildTask

测试,可在服务端打印出options。

第六章 云构建执行流程开发


6-1 云构建任务初始化流程开发

服务端云构建的初始化流程,主要内容为CloudBuildTask这个类

  • npm i -S user-home simple-git fs-extra
  1. // 注意CloudBuildTask类需要传入的第二个参数为ctx
  2. 'use strict';
  3. const path = require('path')
  4. const fse = require('fs-extra')
  5. const userHome = require('user-home')
  6. const Git = require('simple-git')
  7. class CloudBuildTask {
  8. constructor(options,ctx){
  9. this._ctx = ctx
  10. this._name = options.name //项目名称
  11. this._version = options.version //项目版本号
  12. this._repo = options.repo
  13. this._branch = options.branch
  14. this._buildCmd = options.buildCmd //构建命令
  15. this.logger = this._ctx .logger
  16. // 服务器的用户主目录
  17. this._dir = path.resolve(userHome,'.cloudscope-cli','cloudbuild',`${this._name}@${this._version}`) //缓存目录
  18. this._sourceCodeDir = path.resolve(this._dir,this._name) //缓存源码目录
  19. this.logger.info('_dir',this._dir)
  20. this.logger.info('_sourceCodeDir',this._sourceCodeDir)
  21. }
  22. async prepare(){
  23. fse.ensureDirSync(this._dir)
  24. fse.emptyDirSync(this._dir)
  25. this._git = new Git(this._dir)
  26. }
  27. }
  28. module.exports = CloudBuildTask

6-2 云构建任务交互日志开发

本节在CloudBuildTask类中,还未进行开发前,现对错误日志,进行了升级或者说是友好的异常抛出。 首先在CloudBuildTask这个类中,对于返回的格式进行了统一

  1. // app/models/CloudBuildTask.js
  2. const {SUCCESS,FAILED} = require('../constant') //定义了常量
  3. success(msg,data){
  4. return this.response(SUCCESS,msg,data)
  5. }
  6. fail(msg,data){
  7. return this.response(FAILED,msg,data)
  8. }
  9. response(code,message,data){
  10. return {
  11. code,
  12. message,
  13. data
  14. }

然后在 app/io/controller/build.js中。

  1. async function prepare(cloudBuildTask,socket,helper) {
  2. socket.emit('build',helper.parseMsg('prepare',{
  3. message:'开始执行构建前的准备工作'
  4. }))
  5. const prepareRes = await cloudBuildTask.prepare()
  6. if(!prepareRes || Object.is(prepareRes.code,FAILED)){
  7. const msg = prepareRes ? prepareRes.message : 'prepare返回为undefined'
  8. socket.emit('build',helper.parseMsg('prepare failed',{
  9. message: `执行云构建准备工作失败,失败原因:${msg}`
  10. }))
  11. return
  12. }
  13. socket.emit('build',helper.parseMsg('prepare',{
  14. message:'构建前准备工作成功'
  15. }))
  16. }

然后在客户端的models/cloudbuild/lib/index.js,监听的build方法中做了一个优化

  1. build(){
  2. return new Promise((resolve,reject)=>{
  3. this.socket.emit('build')
  4. this.socket.on("build",msg=>{
  5. const parsedMsg = parseMsg(msg)
  6. if(FAILED_CODE.indexOf(parsedMsg.action)>-1){
  7. log.error(parsedMsg.message)
  8. clearTimeout(this.timer)
  9. this.socket.disconnect()
  10. this.socket.close()
  11. }
  12. log.success(parsedMsg.action,parsedMsg.message)
  13. })
  14. this.socket.on('building',msg=>{
  15. const parsedMsg = parseMsg(msg)
  16. log.success(parsedMsg.action,parsedMsg.message)
  17. })
  18. })
  19. }

6-3 服务端源码下载 + 切换分支

在服务端 app/io/controller/build.js下,

  • 我们完成了 await prepare(cloudBuildTask,socket,helper),
  • 接着我们继续实现 await download(cloudBuildTask,socket,helper)
  1. // app/io/controller/build.js
  2. async function download(cloudBuildTask,socket,helper){
  3. socket.emit('build',helper.parseMsg('download repo',{
  4. message:'开始下载源码'
  5. }))
  6. const downloadRes = await cloudBuildTask.download()
  7. if(!downloadRes || Object.is(downloadRes.code,FAILED)){ // downlod下载失败
  8. socket.emit('build',helper.parseMsg('download failed',{
  9. message:'源码下载失败'
  10. }))
  11. return
  12. }else{
  13. socket.emit('build',helper.parseMsg('download repo',{
  14. message:'源码下载成功'
  15. }))
  16. }
  17. }
  18. // app/models/CloudBuildTask.js
  19. async download(){
  20. await this._git.clone(this._repo) //clone仓库
  21. this._git = new Git(this._sourceCodeDir) //将git地址更改,生成新的simple git
  22. // 切换分支 git checkout -b dev/1.0.2 origin/dev/1.0.2
  23. await this._git.checkout(['-b',this._branch,`origin/${this._branch}`])
  24. return fs.existsSync(this._sourceCodeDir) ? this.success() : this.failed()
  25. }

然后在客户端执行命令:cloudscope-cli publish —targetPath /Users/liumingzhou/Documents/imoocCourse/Web前端架构师/cloudscope-cli/commands/publish

经过测试,在/User/username/.cloudscoe-cli/cloudbuild/test@1.0.2/test下安装了源码,执行git branch 看到切换到了 开发分支。

6-4 服务端源码依赖安装+命令执行功能封装

与上一节的download流程一样

  1. // app/io/controller/build.js
  2. await install(cloudBuildTask,socket,helper)
  3. async function install(cloudBuildTask,socket,helper) {
  4. socket.emit('build',helper.parseMsg('install',{
  5. message:'开始安装依赖'
  6. }))
  7. const installRes = await cloudBuildTask.install()
  8. if(!installRes || Object.is(installRes.code,FAILED)){ // downlod下载失败
  9. socket.emit('build',helper.parseMsg('install failed',{
  10. message:'安装依赖失败'
  11. }))
  12. return
  13. }else{
  14. socket.emit('build',helper.parseMsg('install',{
  15. message:'安装依赖成功'
  16. }))
  17. }
  18. }
  19. // app/models/CloudBuildTask.js
  20. async install(){
  21. let res = true
  22. res && (res = await this.execCmd('npm install --registry=https://registry.npm.taobao.org'))
  23. return res ? this.success(): this.failed()
  24. }
  25. execCmd(cmd){
  26. // npm install ->['npm','install']
  27. let command = cmd.split(' ')
  28. if(command.length === 0){
  29. return null
  30. }
  31. const firstCommand = command[0]
  32. const leftCommand = command.slice(1) || []
  33. return new Promise((resolve,reject)=>{
  34. const p = exec(firstCommand,leftCommand,{
  35. cwd:this._sourceCodeDir
  36. },{stdio:'pipe'})
  37. p.on('error',e=>{
  38. this._ctx.logger.error('build error',e)
  39. resolve(fasle)
  40. })
  41. p.on('exit',c=>{
  42. this._ctx.logger.info('build exit',c)
  43. resolve(true)
  44. })
  45. p.stdout.on('data',data => {
  46. this._ctx.socket.emit('building',data.toString())
  47. })
  48. p.stderr .on('data', data =>{
  49. this._ctx.socket.emit('building',data.toString())
  50. })
  51. })
  52. }
  53. function exec(command,args,options){
  54. const win32 = process.platform === 'win32';
  55. const cmd = win32 ? 'cmd': command
  56. const cmdArgs = win32 ? ['/c'].concat(command,args) : args;
  57. return require('child_process').spawn(cmd, cmdArgs,options || {})
  58. }

6-5 云构建任务执行逻辑开发

  1. // app/io/controller/build.js
  2. await build(cloudBuildTask,socket,helper)
  3. async function build(cloudBuildTask,socket,helper) {
  4. socket.emit('build',helper.parseMsg('build',{
  5. message:'开始启动云构建'
  6. }))
  7. const buildRes = await cloudBuildTask.build()
  8. if(!buildRes || Object.is(buildRes.code,FAILED)){ // downlod下载失败
  9. socket.emit('build',helper.parseMsg('build failed',{
  10. message:'云构建任务执行失败'
  11. }))
  12. return
  13. }else{
  14. socket.emit('build',helper.parseMsg('build',{
  15. message:'云构建任务执行成功'
  16. }))
  17. }
  18. }
  19. // app/models/CloudBuildTask.js
  20. async build(){
  21. let res = true
  22. if(checkCommand(this._buildCmd)){
  23. res = await this.execCmd(this._buildCmd)
  24. }else{
  25. res = false
  26. }
  27. return false ? this.success():this.failed()
  28. }
  29. function checkCommand(command){
  30. if(command){
  31. const commands = command.split(' ')
  32. if(commands.length === 0 || ['npm','cnpm'].indexOf(commands[0])<0){
  33. return false
  34. }
  35. return true
  36. }
  37. return false
  38. }

最后在客户端经过测试,看到 build的dist目录没有构建成功:这是因为我的test源码不是一个可以打包的项目。 于是重写创建项目,并且publish 的时候输入参数 —refreshServer —refreshOwner ,构建成功。