部署狗
- 適用與個人與小團(tuán)隊的輕量級自動部署工具
- 基于electron+vue+element開發(fā)
- github
技術(shù)棧
- electron-vue
開發(fā)
$ npm install
$ npm run dev
先來一波圖
項目管理
添加項目
發(fā)布進(jìn)度
部署流程
安裝包
具體代碼:
- 部署代碼 deploy.js (electron主進(jìn)程中執(zhí)行)
const path = require('path');
const node_ssh = require('node-ssh');
const zipFile = require('compressing')// 壓縮zip
let SSH = new node_ssh(); // 生成ssh實例
let mainWindow = null; // 窗口實例,用于向向渲染進(jìn)程通信
// 部署流程入口
const deploy = async (config, mainWindows) => {
mainWindow = mainWindows
await startZip(config);
await connectSSH(config);
await uploadZipBySSH(config)
}
//壓縮代碼
const startZip = async (config) => {
return new Promise((resolve, reject) => {
let { distPath } = config;
let distZipPath = path.resolve(distPath, `../dist.zip`);
mainWindow.send('deploy', '本地項目開始壓縮')
zipFile.zip.compressDir(distPath, distZipPath).then(res => {
mainWindow.send('deploy', `本地項目壓縮完成:${distZipPath}`)
resolve()
}).catch(err => {
mainWindow.send('deploy', `壓縮失敗${err}`)
reject()
})
})
}
//連接服務(wù)器
const connectSSH = async (config) => {
return new Promise((resolve, reject) => {
mainWindow.send('deploy', `正在連接服務(wù)器:${config.host}`)
SSH.connect({
host: config.host,
username: config.username,
password: config.password // 密碼登錄 方式二
}).then(res => {
mainWindow.send('deploy', `連接服務(wù)器成功:${config.host}`)
resolve()
}).catch(err => {
mainWindow.send('deploy', `連接服務(wù)器失敗:${err}`)
reject()
})
})
}
//清空線上目標(biāo)目錄里的舊文件
const clearOldFile = async (config) => {
mainWindow.send('deploy', `準(zhǔn)備清空服務(wù)器部署目錄${config.webDir}內(nèi)的文件`)
const commands = ['ls', 'rm -rf *'];
await Promise.all(commands.map(async (item) => {
return await SSH.execCommand(item, { cwd: config.webDir });
}));
mainWindow.send('deploy', `清空服務(wù)器目錄${config.webDir}內(nèi)的文件完成`)
}
//上傳zip文件到服務(wù)器
const uploadZipBySSH = async (config) => {
let distZipPath = path.resolve(config.distPath, `../dist.zip`);
//線上目標(biāo)文件清空
await clearOldFile(config);
try {
await SSH.putFiles([{ local: distZipPath, remote: config.webDir + '/dist.zip' }]); //local 本地 ; remote 服務(wù)器 ;
mainWindow.send('deploy', `上傳文件到服務(wù)器成功:${config.webDir}`)
await SSH.execCommand('unzip -o dist.zip && rm -f dist.zip', { cwd: config.webDir }); //解壓
mainWindow.send('deploy', `解壓上傳到服務(wù)器的文件成功`)
await SSH.execCommand(`rm -rf ${config.webDir}/dist.zip`, { cwd: config.webDir }); //解壓完刪除線上壓縮包
mainWindow.send('deploy', `刪除上傳到服務(wù)器的文件成功`)
//將解壓后的文件夾內(nèi)的所有文件移動到目標(biāo)目錄
var dir = path.basename(path.join(config.distPath))
mainWindow.send('deploy', `將${config.webDir}/${dir}/內(nèi)解壓的文件移動到目錄${config.webDir}`)
await SSH.execCommand(`mv - f ${config.webDir}/${dir}/* ${config.webDir}`);
await SSH.execCommand(`rm -rf ${config.webDir}/${dir}`); //移出后刪除 dist 文件夾
mainWindow.send('deploy', `全部完成`)
SSH.dispose(); //斷開連接
} catch (error) {
mainWindow.send('deploy', `文件上傳到服務(wù)器失敗:${error}`)
// process.exit(); //退出流程
}
}
export default deploy
- 主進(jìn)程進(jìn)行監(jiān)聽與渲染進(jìn)行發(fā)送的命令
// 監(jiān)聽前臺傳來的deploy命令
ipcMain.on('deploy', (e, data) => {
deploy(data, mainWindow)
});
- 前臺部分代碼
<template>
<div id="wrapper">
<el-row :gutter="20" class="pro-list">
<el-col :span="12" v-for="(item, index) in dataList" :key="index">
<el-card class="box-card">
<ul class="prolist">
<li>
<span class="label">項目名稱:</span>
<span class="info">{{ item.projectName }}</span>
</li>
<li>
<span class="label">服務(wù)器地址:</span>
<span class="info">{{ item.host }}</span>
</li>
// ...other
</ul>
<div class="btns">
<el-button icon="el-icon-s-promotion" @click="deploy(item)" type="primary">發(fā)布</el-button>
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import { ipcRenderer } from "electron";
export default {
name: "prolist",
created() {
this.getDb();
// 接收主進(jìn)程部署過程 中的 過程信息
ipcRenderer.on("deploy", (event, arg) => {
this.activities.unshift({
content:arg,
timestamp: new Date().toLocaleTimeString()
});
});
},
data() {
return {
dataList: [],
activities: []
};
},
methods: {
// 部署
deploy(config) {
// 發(fā)送打包命令 給 主進(jìn)程
ipcRenderer.send("deploy", config);
},
remove(config) {
// 刪除項目
}
}
};
</script>
僅供大家學(xué)習(xí)參考
所有數(shù)據(jù)存在本地lowdb中,所以不用擔(dān)心安全問題