1 Star 24 Fork 6

virtual1680 / q-admin

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
deploy.js 9.48 KB
一键复制 编辑 原始数据 按行查看 历史
qinhongyang 提交于 2022-06-27 09:24 . style: 🎨 change singleQuote
// 测试环境【华为鲲鹏服务器】
// const huawei_kunpeng = {
// host: "10.10.1.32",
// password: "Leyun@123",
// catalog: "/home/app/pages/park/mp/",
// port: 22,
// username: "root",
// privateKey: null
// };
// 测试环境【本地测试环境】
const local = {
host: '10.10.1.32',
password: 'Leyun@123',
catalog: '/usr/share/nginx/html',
port: 22,
username: 'root',
privateKey: null
};
// 全局配置
const Config = {
// publishEnv: pro,
publishEnv: [local], // 发布环境,可填写多个,也可只填写一个
buildDist: 'dist', // 前端文件打包之后的目录,默认dist
buildCommand: 'npm run build', // 打包前端文件的命令
readyTimeout: 20000, // ssh连接超时时间
deleteFile: true // 是否删除线上上传的dist压缩包
};
const { exec } = require('child_process');
const path = require('path');
const archiver = require('archiver');
const fs = require('fs');
const Client = require('ssh2').Client;
// 前端打包文件的目录
// const dir = path.resolve(__dirname, Config.buildDist);
/**
* ssh连接
*/
class SSH {
constructor({ host, port, username, password, privateKey, agent }) {
this.server = {
host,
port,
username,
password,
privateKey
};
this.hasAgent = agent && agent.host && agent.port && agent.username;
if (this.hasAgent) {
this.connAgent = new Client(); // 连接跳板机
this.conn = new Client(); // 连接目标机
this.agent = agent;
} else {
this.conn = new Client();
}
}
// 连接服务器
connectServer() {
return new Promise((resolve, reject) => {
let conn = this.conn;
if (this.hasAgent) {
conn = this.connAgent;
}
conn
.on('ready', () => {
if (this.hasAgent) {
// Alternatively, you could use netcat or socat with exec() instead of
// forwardOut()
console.log('----连接跳板机成功----');
conn.forwardOut('127.0.0.1', 12345, this.agent.host, this.agent.port, (err, stream) => {
if (err) {
conn.end();
reject({
success: false,
error: err
});
}
// 连接目标机
this.conn
.on('ready', () => {
console.log('----连接目标机成功----');
resolve({
success: true
});
})
.on('error', err => {
reject({
success: false,
error: err
});
})
.on('end', () => {
console.log('target ssh connect end!');
})
.on('close', () => {
console.log('target ssh connect close');
})
.connect({
sock: stream,
username: this.agent.username,
password: this.agent.password
});
});
} else {
resolve({
success: true
});
}
})
.on('error', err => {
reject({
success: false,
error: err
});
})
.on('end', () => {
console.log('----SSH连接已结束----');
})
.on('close', () => {
console.log('----SSH连接已关闭----');
})
.connect(this.server);
});
}
// 上传文件
uploadFile({ localPath, remotePath }) {
return new Promise((resolve, reject) => {
return this.conn.sftp((err, sftp) => {
if (err) {
reject({
success: false,
error: err
});
} else {
sftp.fastPut(localPath, remotePath, (err, result) => {
if (err) {
reject({
success: false,
error: err
});
}
resolve({
success: true,
result
});
});
}
});
});
}
// 执行ssh命令
execSsh(command) {
return new Promise((resolve, reject) => {
return this.conn.exec(command, (err, stream) => {
if (err || !stream) {
reject({
success: false,
error: err
});
} else {
stream
.on('close', () => {
resolve({
success: true
});
})
.on('data', function (data) {
console.log(data.toString());
})
.stderr.on('data', function (data) {
resolve({
success: false,
error: data.toString()
});
});
}
});
});
}
// 结束连接
endConn() {
this.conn.end();
if (this.connAgent) {
this.connAgent.end();
}
}
}
/*
* 本地操作
* */
class File {
constructor(fileName) {
this.fileName = fileName;
}
// 删除本地文件
deleteLocalFile() {
return new Promise((resolve, reject) => {
fs.unlink(this.fileName, function (error) {
if (error) {
reject({
success: false,
error
});
} else {
resolve({
success: true
});
}
});
});
}
// 压缩文件夹下的所有文件
zipFile(filePath) {
return new Promise((resolve, reject) => {
// 创建文件输出流
let output = fs.createWriteStream(__dirname + '/' + this.fileName);
let archive = archiver('zip', {
zlib: { level: 9 } // 设置压缩级别
});
// 文件输出流结束
output.on('close', function () {
console.log(`----压缩文件总共 ${archive.pointer()} 字节----`);
console.log('----压缩文件夹完毕----');
resolve({
success: true
});
});
// 数据源是否耗尽
output.on('end', function () {
console.error('----压缩失败,数据源已耗尽----');
reject();
});
// 存档警告
archive.on('warning', function (err) {
if (err.code === 'ENOENT') {
console.error('----stat故障和其他非阻塞错误----');
} else {
console.error('----压缩失败----');
}
reject(err);
});
// 存档出错
archive.on('error', function (err) {
console.error('----存档错误,压缩失败----');
console.error(err);
reject(err);
});
// 通过管道方法将输出流存档到文件
archive.pipe(output);
// 打包dist里面的所有文件和目录
archive.directory(filePath, false);
// archive.directory(`../${Config.buildDist}/`, false);
// 完成归档
archive.finalize();
});
}
// 打包本地前端文件
buildProject() {
console.log('----开始编译打包文件,请耐心等待----');
return new Promise((resolve, reject) => {
exec(Config.buildCommand, async (error, stdout, stderr) => {
if (error) {
console.error(error);
reject({
error,
success: false
});
} else if (stdout) {
resolve({
stdout,
success: true
});
} else {
console.error(stderr);
reject({
error: stderr,
success: false
});
}
});
});
}
// 停止程序之前需删除本地压缩包文件
stopProgress() {
this.deleteLocalFile()
.catch(e => {
console.error('----删除本地文件失败,请手动删除----');
console.error(e);
})
.then(() => {
console.log('----已删除本地压缩包文件----');
});
}
}
// SSH连接,上传,解压,删除等相关操作
async function sshUpload(sshConfig, fileName) {
let sshCon = new SSH(sshConfig);
let sshRes = await sshCon.connectServer().catch(e => {
console.error(e);
});
if (!sshRes || !sshRes.success) {
console.error('----连接服务器失败,请检查用户名密码是否正确以及服务器是否已开启远程连接----');
return false;
}
console.log('----连接服务器成功,开始上传文件----');
let uploadRes = await sshCon
.uploadFile({
localPath: path.resolve(__dirname, fileName),
remotePath: sshConfig.catalog + '/' + fileName
})
.catch(e => {
console.error(e);
});
if (!uploadRes || !uploadRes.success) {
console.error('----上传文件失败,请重新上传----');
return false;
}
console.log('----上传文件成功,开始解压文件----');
let zipRes = await sshCon.execSsh(`unzip -o ${sshConfig.catalog + '/' + fileName} -d ${sshConfig.catalog}`).catch(() => {});
if (!zipRes || !zipRes.success) {
console.error('----解压文件失败,请手动解压zip文件----');
console.error(`----错误原因:${zipRes.error}----`);
}
if (Config.deleteFile) {
console.log('----解压文件成功,开始删除上传的压缩包----');
// 注意:rm -rf为危险操作,请勿对此段代码做其他非必须更改
let deleteZipRes = await sshCon.execSsh(`rm -rf ${sshConfig.catalog + '/' + fileName}`).catch(() => {});
if (!deleteZipRes || !deleteZipRes.success) {
console.error('----删除文件失败,请手动删除zip文件----');
console.error(`----错误原因:${deleteZipRes.error}----`);
}
}
// 结束ssh连接
sshCon.endConn();
}
// 执行前端部署
(async () => {
// 压缩包的名字
let date = new Date();
let year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
let timeStr = `${year}_${month}_${day}`;
const fileName = `${Config.buildDist}-` + timeStr + '-' + Math.random().toString(16).slice(2) + '.zip';
let file = new File(fileName);
// 打包文件
let buildRes = await file.buildProject().catch(e => {
console.error(e);
});
if (!buildRes || !buildRes.success) {
console.error('----编译打包文件出错----');
return false;
}
console.log(buildRes.stdout);
console.log('----编译打包文件完成----');
// 压缩文件
let res = await file.zipFile(`${Config.buildDist}/`).catch(() => {});
if (!res || !res.success) return false;
console.log('----开始进行SSH连接----');
if (Config.publishEnv instanceof Array && Config.publishEnv.length) {
for (let i = 0; i < Config.publishEnv.length; i++) {
await sshUpload(Config.publishEnv[i], fileName);
}
} else {
await sshUpload(Config.publishEnv, fileName);
}
console.log('----部署成功,正在为您删除本地压缩包----');
file.stopProgress();
})();
1
https://gitee.com/virtual1680/q-admin.git
git@gitee.com:virtual1680/q-admin.git
virtual1680
q-admin
q-admin
master

搜索帮助