Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions deploy.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module.exports = {
projectName: 'test',
privateKey: '/Users/bin/.ssh/id_rsa',
passphrase: '',
dev: {
name: '开发环境',



port: 22,
username: 'yoyo',
password: '123456.Yoyo',
webDir: '/home/yoyo/temp/deploy',
remoteBeforeCommand: 'ls',
remoteAfterCommand: 'echo "remoteAfterCommand"',
isRemoveRemoteFile: false,
uploadCommand: 'ls',

servers: [{
host: '192.168.16.21',
}],
distPath: './bin',
isRemoveRemoteFile: true
}
}
225 changes: 196 additions & 29 deletions lib/commands/deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ const archiver = require('archiver')
const { NodeSSH } = require('node-ssh')
const childProcess = require('child_process')
const { deployConfigPath } = require('../config')

const {
checkDeployConfigExists,
log,
succeed,
error,
underline
} = require('../utils')
const { resolve } = require('path')

const ssh = new NodeSSH()
const maxBuffer = 5000 * 1024
Expand All @@ -32,21 +34,36 @@ const confirmDeploy = (message) => {

// 检查环境是否正确
const checkEnvCorrect = (config, env) => {

const keys = [
'name',
'script',
'distPath',
]

const serverKeys = [
'privateKey',
'host',
'port',
'username',
'distPath',
'webDir'
]
'password',
'webDir',
'remoteBeforeCommand',
'remoteAfterCommand',
'uploadCommand'
];

const serverRequiredKeys = [
'host',
'port',
'username',
'webDir',
];

if (
config &&
(function () {
const { privateKey, password } = config
if (!privateKey && !password) {
const { privateKey, password, servers } = config
if (!privateKey && !password && !(servers && servers.length > 0 && servers[0].password)) {
error(
`配置错误: 请配置 ${underline('privateKey')} 或 ${underline(
'passwrod'
Expand All @@ -57,6 +74,20 @@ const checkEnvCorrect = (config, env) => {
return true
})()
) {

if (!(config.servers && config.servers.length)) {
config.servers = [{}];
}

// 填充server字段
config.servers.forEach(server => {
serverKeys.forEach(key => {
if ('undefined' !== typeof config[key] && 'undefined' === typeof server[key]) {
server[key] = config[key];
}
})
});

keys.forEach((key) => {
if (!config[key] || config[key] === '/') {
error(
Expand All @@ -67,6 +98,23 @@ const checkEnvCorrect = (config, env) => {
process.exit(1)
}
})

// 校验server信息
config.servers.forEach(server => {
serverRequiredKeys.forEach(key => {
if (!server[key] || server[key] === '/') {
error(
`配置错误: ${underline(`${env}环境`)} ${underline(
`${key}属性`
)} 配置不正确`
)
process.exit(1)
}
})
});

console.log(config);

} else {
error('配置错误: 未指定部署环境或指定部署环境不存在')
process.exit(1)
Expand Down Expand Up @@ -134,10 +182,10 @@ const buildZip = async (config, index) => {
}

// 连接ssh
const connectSSH = async (config, index) => {
const connectSSH = (server) => async (config, index) => {
try {
log(`(${index}) ssh连接 ${underline(config.host)}`)
await ssh.connect(config)
log(`(${index}) ssh连接 ${underline(server.host)}`)
await ssh.connect(server)
succeed('ssh连接成功')
} catch (e) {
error(e)
Expand All @@ -146,13 +194,15 @@ const connectSSH = async (config, index) => {
}

// 上传本地文件
const uploadLocalFile = async (config, index) => {
const uploadLocalFile = (server) => async (config, index) => {
try {
const { webDir, host } = server;

const localFileName = `${config.distPath}.zip`
const remoteFileName = `${config.webDir}.zip`
const remoteFileName = `${webDir}.zip`
const localPath = `${process.cwd()}/${localFileName}`

log(`(${index}) 上传打包zip至目录 ${underline(remoteFileName)}`)
log(`(${index}) 上传打包zip至目录 ${host} ${underline(remoteFileName)}`)

const spinner = ora('正在上传中\n')

Expand All @@ -171,11 +221,11 @@ const uploadLocalFile = async (config, index) => {
}

// 删除远程文件
const removeRemoteFile = async (config, index) => {
const removeRemoteFile = (server) => async (config, index) => {
try {
const { webDir } = config
const { webDir, host } = server

log(`(${index}) 删除远程文件 ${underline(webDir)}`)
log(`(${index}) 删除远程文件 ${host} ${underline(webDir)}`)

await ssh.execCommand(`rm -rf ${webDir}`)

Expand All @@ -186,13 +236,112 @@ const removeRemoteFile = async (config, index) => {
}
}

// 执行后置远程命令
const runAfterRemoteCommand = (server) => async (config, index) => {
try {
const { remoteAfterCommand, host } = server

log(`(${index}) 执行后置远程命令 ${host} ${underline(remoteAfterCommand)}`)

const result = await ssh.execCommand(remoteAfterCommand)


if (result.stdout) {
log(result.stdout)
}

if (result.stderr) {
error(result.stderr)
}
if (result.code) {
error('执行后置远程命令失败')
const answers = await confirmDeploy(
`${underline(projectName)} 执行后置远程命令失败 是否继续?`
)

if (!answers.confirm) {
process.exit(1)
}
}

succeed('执行后置远程命令成功')
} catch (e) {
error(e)
process.exit(1)
}
}

// 执行前置远程命令
const runBeforeRemoteCommand = (server) => async (config, index) => {
try {
const { remoteBeforeCommand, host } = server

log(`(${index}) 执行前置远程命令 ${host} ${underline(remoteBeforeCommand)}`)

const result = await ssh.execCommand(remoteBeforeCommand)

if (result.stdout) {
log(result.stdout)
}

if (result.stderr) {
error(result.stderr)
}
if (result.code) {
error('执行前置远程命令失败')

const answers = await confirmDeploy(
`${underline(projectName)} 执行前置远程命令失败 是否继续?`
)

if (!answers.confirm) {
process.exit(1)
}
}

succeed('执行前置远程命令成功')
} catch (e) {
error(e)
process.exit(1)
}
}


// 执行本地命令
const runLocalCommand = (tip, command) => async (config, index) => {
try {

log(`(${index}) ${tip} ${underline(command)}`)

return new Promise((resolve, reject) => {
childProcess.exec(
command,
{ cwd: process.cwd(), maxBuffer: maxBuffer },
(e, stdout, stderr) => {
if (e === null) {
log(stdout);
succeed(`${tip}成功`)
resolve()
} else {
log(stderr);
reject(e.message)
}
}
)
});
} catch (e) {
error(e)
process.exit(1)
}
}

// 解压远程文件
const unzipRemoteFile = async (config, index) => {
const unzipRemoteFile = (server) => async (config, index) => {
try {
const { webDir } = config
const { webDir, host } = server
const remoteFileName = `${webDir}.zip`

log(`(${index}) 解压远程文件 ${underline(remoteFileName)}`)
log(`(${index}) 解压远程文件 ${host} ${underline(remoteFileName)}`)

await ssh.execCommand(
`unzip -o ${remoteFileName} -d ${webDir} && rm -rf ${remoteFileName}`
Expand All @@ -206,7 +355,7 @@ const unzipRemoteFile = async (config, index) => {
}

// 删除本地打包文件
const removeLocalFile = (config, index) => {
const removeLocalBuildFile = (config, index) => {
const localPath = `${process.cwd()}/${config.distPath}`

log(`(${index}) 删除本地打包目录 ${underline(localPath)}`)
Expand All @@ -226,28 +375,45 @@ const removeLocalFile = (config, index) => {
}

remove(localPath)
fs.unlinkSync(`${localPath}.zip`)
succeed('删除本地打包目录成功')
}

// 删除本地打包zip文件
const removeLocalFile = (config, index) => {
const localPath = `${process.cwd()}/${config.distPath}`

log(`(${index}) 删除本地打包zip文件 ${localPath}.zip`)

fs.unlinkSync(`${localPath}.zip`)
succeed('删除本地打包zip文件')
}

// 断开ssh
const disconnectSSH = () => {
ssh.dispose()
}

// 创建任务列表
const createTaskList = (config) => {
const { isRemoveRemoteFile = true } = config

taskList = []
taskList.push(execBuild)
taskList.push(buildZip)
taskList.push(connectSSH)
taskList.push(uploadLocalFile)
isRemoveRemoteFile && taskList.push(removeRemoteFile)
taskList.push(unzipRemoteFile)
taskList.push(removeLocalFile)
taskList.push(disconnectSSH)

config.script && taskList.push(execBuild);

config.servers.forEach(server => {
server.uploadCommand || taskList.push(buildZip);
taskList.push(connectSSH(server))
server.uploadCommand && taskList.push(runLocalCommand('上传文件', server.uploadCommand));
server.uploadCommand || taskList.push(uploadLocalFile(server));
server.remoteBeforeCommand && taskList.push(runBeforeRemoteCommand(server));
server.isRemoveRemoteFile && taskList.push(removeRemoteFile(server))
server.uploadCommand || taskList.push(unzipRemoteFile(server));
server.remoteAfterCommand && taskList.push(runAfterRemoteCommand(server));
taskList.push(disconnectSSH)
server.uploadCommand || taskList.push(removeLocalFile)
})
config.script && taskList.push(removeLocalBuildFile)
config.script && taskList.push(removeLocalFile)
}

// 执行任务列表
Expand All @@ -265,6 +431,7 @@ module.exports = {
if (checkDeployConfigExists()) {
const config = require(deployConfigPath)
const projectName = config.projectName

const envConfig = Object.assign(config[env], {
privateKey: config.privateKey,
passphrase: config.passphrase
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "deploy-cli-service",
"version": "1.1.2",
"version": "1.1.5",
"description": "前端一键自动化部署脚手架服务",
"main": "lib/service.js",
"homepage": "https://github.com/fuchengwei/deploy-cli-service",
Expand Down