生成壓縮包並上傳指定分支自動化腳本
- 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 可以將打包壓縮繼承到一起。