生成压缩包并上传指定分支自动化脚本

  • 2019 年 10 月 5 日
  • 筆記

生成压缩包并上传指定分支自动化脚本

业务需求

  • 项目测试或部署上线时,需要从主分支拉取打包后的压缩包
  • 当前存在开发分支dev , 主分支 marster , 当处于开发分支时,执行脚本命令 zip 自动完成 ,压缩包生成, 分支切换, 文件更新及提交

执行流程

graph TD    生成压缩包 --> 保存压缩包到缓存目录  保存压缩包到缓存目录 --> 切换到主分支  切换到主分支 --> 将缓存拷贝到主分支目录  将缓存拷贝到主分支目录 --> 提交  提交 --> 切回开发分支  切回开发分支 --> 删除缓存  删除缓存 --> 保存新版本信息

脚本目录

  • 当前以vue 项目为例
- root      - script          - index.js // 入口          - createZip.js // 生成压缩包          - cmmds.js // 执行git命令          - utils.js // 工具包          - version.js // 版本更新          - color.js // 信息输出          - config.json // 配置文件

源码

  • /createZip.js
/**   * 创建压缩包   */  const fs = require('fs')  const archiver = require('archiver')    const events = {      warning(err){      console.log(`warning: ${err}`)    },      error(err){      console.log(`error: ${err}`)    }  }    /**   * 新建zip压缩包   * @param { string } entryPath 被打包文件地址   * @param { string } outPath  打包输出地址   */  function createZip(entryPath, outPath){    const outBuff = fs.createWriteStream(outPath)      const archive = archiver('zip', {      zlib: { level: 9 }    })      Object.entries(events).map(({key, fn}) => archive[key] = fn )        archive.pipe(outBuff);    archive.directory(entryPath, false)    archive.finalize()    }    module.exports = {    createZip  }
  • /cmmds.js
const util = require('util')  const exec = util.promisify(require('child_process').exec);    function splitLineFeed(str){      return str.split('n')  }    function loopPrint(str){      splitLineFeed(str).map(item => console.log(item))  }    /**   * 命令仓库   */  class Commds{        constructor(){          this.commds = []      }        /**       * 注册命令       * 参数参考 node child_process/exec       */      register(cmmd, options, callback){            // 调整参数          if(typeof options === 'function'){              callback = options              options = null          }            if(Array.isArray(cmmd)){              this.cmmds.concat(cmmd)          }else{              this.commds.push({ cmmd, options, callback })          }            return this      }        /**       * 按顺序调用命令       */      run(){          return this.commds.reduce((acc, next) => acc.then(() => exec(next['cmmd'], next['options']).then(next['callback']) ), Promise.resolve() )      }        /**       * 清空命令       */      clear(){          this.commds = []      }        /**       * 非 new 新建对象       */      static of(){          return new Commds()      }    }    module.exports = {        splitLineFeed,      loopPrint,      Commds    }
  • /utils.js
const fs = require('fs')  const util = require('util')  const path = require('path')  const { printSuccess } = require('./color')    /**   * 拷贝文件   * @param { string } source 原文件路径   * @param { string } target 目标文件路径   */  function copyFile(source, target){      source = path.resolve(__dirname, source)      target = path.resolve(__dirname, target)      return () => util.promisify(fs.copyFile)(source,target).then(() => printSuccess(`copy success from ${source} to ${target}`) )  }    /**   * 删除文件   * @param { string } filePath 文件路径   */  function delFile(filePath){      return () => util.promisify(fs.unlink)(filePath)  }    /**   * 写入配置   * @param { string } path 保存路径   * @param { json } data 保存数据   */  function updateConfig(path, data){      return util.promisify(fs.writeFile)(path, JSON.stringify(data,null, 2), {flag:'w',encoding:'utf-8',mode:'0666'}).then(() => printSuccess('save config'))  }    module.exports = {      copyFile,      delFile,      updateConfig  }
  • /version.js
/**   * 版本更新   * @param { string } version 版本号 0.0.1   */  function updateVersion(version, separator='.'){      const nums = String.prototype.split.apply(version, [separator])      nums.push(parseInt(nums.pop()) + 1)      return nums.join(separator)  }    module.exports = {      updateVersion  }
  • /color.js
const chalk = require('chalk')  /**   * 彩色提示   */     function print(msg, type='green'){      console.log('>>>', chalk[type](msg))   }     function printError(error){      print(error, 'res')   }     function printSuccess(msg){      print(msg, 'green')   }     function printWarning(warning){      print(warning, 'yellow')   }    module.exports = {      print,      printError,      printSuccess,      printWarning  }
  • /index.js
const path = require('path')  const config = require('./config.json')  const { printError, printSuccess } = require('./color')  const { createZip } = require('./createZip')  const { zip } = config  const { Commds } = require('./cmmds')  const { updateVersion } = require('./version')  const { copyFile, delFile, updateConfig } = require('./utils')    const newVersion = updateVersion(config.varsion)  const checkoutToMarster =  Commds.of().register(`git checkout ${zip.masterBranch}`, () =>printSuccess(`checkout to ${zip.masterBranch}`))  const updateMarster =  Commds.of().register(`git add *`).register(`git commit -m "${newVersion}"`).register(`git push`, () => printSuccess('push success'))  const checkoutToDev =  Commds.of().register(`git checkout ${zip.devBranch}`, () => printSuccess(`checkout to ${zip.devBranch}`))  const newConfig = Object.assign({}, config, { varsion: newVersion, lastTime: new Date() })      createZip(zip.entry, zip.catch)  checkoutToMarster.run()                 .then(copyFile(zip.catch, zip.out)) // 将打包文件拷贝到主分支目录                 .then(() => updateMarster.run()) // 提交文件                 .then(() => checkoutToDev.run()) // 切回开发分支                 .then(delFile(zip.catch)) // 删除打包文件                 .then(() => printSuccess(`remove catch from ${zip.catch}`))                 .then(() => updateConfig(path.resolve(__dirname, './config.json'), newConfig)) // 保存版本信息                 .catch(printError)
  • package.json 配置执行命令
{      ...      "scripts":{          "zip": "node ./script"      }  }

总结

最初的想法,希望在开发分支生成压缩包后,通过checkout [branch] [file] 合并文件,但切换分支时,因为生成了新文件,需要保存更新。所以改用将压缩包生成到项目目录外的方式。后期应该会改用临时文件的方式。当前脚本只是对 vue 打包后的文件做压缩上传, 通过 webpack hook 可以将打包压缩继承到一起。