生成壓縮包並上傳指定分支自動化腳本

  • 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 可以將打包壓縮繼承到一起。