格式化

This commit is contained in:
陆柯 2022-06-05 13:30:21 +08:00
parent adb08df677
commit 816f2e3e82

425
deploy.js
View File

@ -9,10 +9,10 @@ const deepmerge = require('deepmerge')
const wo = (global.wo = {
envar: {
deploy: {
fromPath: './webroot',
fromPath: './webroot',
gotoTarget: 'github',
vultr: {
vultr: {
targetType: 'ssh',
host: undefined,
port: 22,
@ -20,7 +20,7 @@ const wo = (global.wo = {
targetDir: 'webroot',
user: undefined,
password: undefined,
key: `${process.env.HOME}/.ssh/id_rsa`,
key: `${process.env.HOME}/.ssh/id_rsa`
},
github: {
targetType: 'git',
@ -30,7 +30,7 @@ const wo = (global.wo = {
gitemail: undefined,
user: undefined,
password: undefined,
key: `${process.env.HOME}/.ssh/id_rsa`,
key: `${process.env.HOME}/.ssh/id_rsa`
}
}
}
@ -39,16 +39,24 @@ const wo = (global.wo = {
// 读取配置文件
try {
let configFile
if (fs.existsSync(configFile=path.join(process.cwd(), 'envar-base-deploy.js'))) {
if (
fs.existsSync(
(configFile = path.join(process.cwd(), 'envar-base-deploy.js'))
)
) {
wo.envar = deepmerge(wo.envar, require(configFile))
console.info(`${configFile} loaded`)
console.info(`- ${configFile} loaded`)
}
if (fs.existsSync(configFile=path.join(process.cwd(), 'envar-base-secret.js'))) {
if (
fs.existsSync(
(configFile = path.join(process.cwd(), 'envar-base-secret.js'))
)
) {
wo.envar = deepmerge(wo.envar, require(configFile))
console.info(`${configFile} loaded`)
console.info(`- ${configFile} loaded`)
}
} catch (err) {
console.error('Loading config files failed: ' + err.message)
console.error('- Loading config files failed: ' + err.message)
}
// 读取命令行参数
@ -61,8 +69,14 @@ commander
.option('-H, --host <host>', `Host IP or domain name of the target server.`)
.option('-P, --port <port>', `Ssh port number of the target server.`)
.option('-b, --targetPath <targetPath>', `Destination path to deploy on the target.`)
.option('-d, --targetDir <targetDir>', `Destination folder to deploy on the target.`)
.option(
'-d, --targetPath <targetPath>',
`Destination path to deploy on the target.`
)
.option(
'-D, --targetDir <targetDir>',
`Destination folder to deploy on the target.`
)
.option('-r, --repo <repo>', `git repo address.`)
.option('-b, --branch <branch>', `git repo branch.`)
@ -70,12 +84,19 @@ commander
.option('-m, --gitemail <gitemail>', `git user email.`)
.option('-u, --user <user>', `User id to login the target server.`)
.option('-k, --key <key>', `User private key file to login the target server.`)
.option('-p, --password <password>', `User password to login the target server. You may have to enclose it in "".`)
.option(
'-k, --key <key>',
`User private key file to login the target server.`
)
.option(
'-p, --password <password>',
`User password to login the target server. You may have to enclose it in "".`
)
.parse(process.argv)
wo.envar.deploy.fromPath = commander.fromPath || wo.envar.deploy.fromPath
wo.envar.deploy.connection = wo.envar.deploy[commander.gotoTarget || wo.envar.deploy.gotoTarget] // 使用用户指定的连接
wo.envar.deploy.connection =
wo.envar.deploy[commander.gotoTarget || wo.envar.deploy.gotoTarget] // 使用用户指定的连接
// 可以用命令行参数覆盖掉配置文件
const connection = {
@ -93,27 +114,35 @@ const connection = {
gitemail: commander.gitemail || wo.envar.deploy.connection.gitemail,
// common
username: commander.user || wo.envar.deploy.connection.user,
privateKey: fs.existsSync(commander.key || wo.envar.deploy.connection.key) ? (commander.key || wo.envar.deploy.connection.key) : undefined,
privateKey: fs.existsSync(commander.key || wo.envar.deploy.connection.key)
? commander.key || wo.envar.deploy.connection.key
: undefined,
password: commander.password || wo.envar.deploy.connection.password,
tryKeyboard: true,
onKeyboardInteractive: (name, instructions, lang, prompts, finish) => { // 不起作用
if (prompts.length > 0 && prompts[0].prompt.toLowerCase().includes('password')) {
onKeyboardInteractive: (name, instructions, lang, prompts, finish) => {
// 不起作用
if (
prompts.length > 0 &&
prompts[0].prompt.toLowerCase().includes('password')
) {
finish([password])
}
},
url: wo.envar.deploy.connection.url
}
console.log(` deploy from ${wo.envar.deploy.fromPath} to ${JSON.stringify(connection)}`)
console.log(
` deploy from ${wo.envar.deploy.fromPath} to ${JSON.stringify(connection)}`
)
if (connection.targetType==='ssh') {
if (connection.targetType === 'ssh') {
deployToSsh(connection)
}else if (connection.targetType==='git'){
} else if (connection.targetType === 'git') {
deployToGit(connection)
}
/** ********************** 连接到 Ssh主机拷贝文件到指定路径 ************* **/
function deployToSsh(connection){
function deployToSsh (connection) {
const ssh = new (require('node-ssh'))()
function subDirs (path) {
@ -129,60 +158,92 @@ function deployToSsh(connection){
})
return dirs
}
const necessaryPath = (path) => {
const necessaryPath = path => {
return subDirs(path)
.map(it => it.replace(path, ''))
.filter(it => it)
.map(it => it.split('/').filter(it => it))
}
ssh.connect(connection).then(async () => {
console.log(`[ mv ${connection.targetDir} ${connection.targetDir}-backup-${new Date().toISOString()} ... ]`)
await ssh.execCommand(`mv ${connection.targetDir} ${connection.targetDir}-backup-${new Date().toISOString()}`, { cwd: connection.targetPath })
console.log(`[ mkdir ${connection.targetDir} ... ]`)
await ssh.execCommand(`mkdir ${connection.targetDir}`, { cwd: connection.targetPath })
const toCreate = necessaryPath(path.join('./', wo.envar.deploy.fromPath))
for (const name of toCreate) {
console.log(`[ mkdir ${connection.targetDir}/${name.join('/')} ... ]`)
await ssh.execCommand(`mkdir ${connection.targetDir}/${name.join('/')}`, { cwd: connection.targetPath })
}
let err
console.log(`[ Upload to ${connection.targetPath}/${connection.targetDir} ... ]`)
await ssh.putDirectory(path.join('./', wo.envar.deploy.fromPath), `${connection.targetPath}/${connection.targetDir}`, {
concurrency: 10,
recursive: true,
validate: itemPath => {
const baseName = path.basename(itemPath)
return !baseName.endsWith('.map')
},
tick: (fromPath, remotePath, error) => {
console.log(`Uploading "${fromPath}" ===> "${remotePath}" ${error || 'succeeded!'}`)
err = error
},
})
ssh.dispose()
if (err) {
console.error(`🤷‍♀️🤷‍♀️🤷‍♀️ Failed deploy ${wo.envar.deploy.fromPath} to ${connection.targetPath}/${connection.targetDir} 🤷‍♀️🤷‍♀️🤷‍♀️`)
process.exit(1)
} else {
console.info(`😊😊😊 Successfully deployed [${wo.envar.deploy.fromPath}] to [${connection.targetPath}/${connection.targetDir}] 😊😊😊`)
if (connection.url){
console.info(`😊😊😊 ${connection.url} 😊😊😊`)
ssh
.connect(connection)
.then(async () => {
console.log(
`[ mv ${connection.targetDir} ${
connection.targetDir
}-backup-${new Date().toISOString()} ... ]`
)
await ssh.execCommand(
`mv ${connection.targetDir} ${
connection.targetDir
}-backup-${new Date().toISOString()}`,
{ cwd: connection.targetPath }
)
console.log(`[ mkdir ${connection.targetDir} ... ]`)
await ssh.execCommand(`mkdir ${connection.targetDir}`, {
cwd: connection.targetPath
})
const toCreate = necessaryPath(path.join('./', wo.envar.deploy.fromPath))
for (const name of toCreate) {
console.log(`[ mkdir ${connection.targetDir}/${name.join('/')} ... ]`)
await ssh.execCommand(
`mkdir ${connection.targetDir}/${name.join('/')}`,
{ cwd: connection.targetPath }
)
}
process.exit()
}
}).catch(err => {
console.error(err)
ssh.dispose()
console.error(`🤷‍♀️🤷‍♀️🤷‍♀️ Failed deploy [${wo.envar.deploy.fromPath}] to [${connection.targetPath}/${connection.targetDir}] 🤷‍♀️🤷‍♀️🤷‍♀️`)
process.exit(1)
})
let err
console.log(
`[ Upload to ${connection.targetPath}/${connection.targetDir} ... ]`
)
await ssh.putDirectory(
path.join('./', wo.envar.deploy.fromPath),
`${connection.targetPath}/${connection.targetDir}`,
{
concurrency: 10,
recursive: true,
validate: itemPath => {
const baseName = path.basename(itemPath)
return !baseName.endsWith('.map')
},
tick: (fromPath, remotePath, error) => {
console.log(
`Uploading "${fromPath}" ===> "${remotePath}" ${error ||
'succeeded!'}`
)
err = error
}
}
)
ssh.dispose()
if (err) {
console.error(
`🤷‍♀️🤷‍♀️🤷‍♀️ Failed deploy ${wo.envar.deploy.fromPath} to ${connection.targetPath}/${connection.targetDir} 🤷‍♀️🤷‍♀️🤷‍♀️`
)
process.exit(1)
} else {
console.info(
`😊😊😊 Successfully deployed [${wo.envar.deploy.fromPath}] to [${connection.targetPath}/${connection.targetDir}] 😊😊😊`
)
if (connection.url) {
console.info(`😊😊😊 ${connection.url} 😊😊😊`)
}
process.exit()
}
})
.catch(err => {
console.error(err)
ssh.dispose()
console.error(
`🤷‍♀️🤷‍♀️🤷‍♀️ Failed deploy [${wo.envar.deploy.fromPath}] to [${connection.targetPath}/${connection.targetDir}] 🤷‍♀️🤷‍♀️🤷‍♀️`
)
process.exit(1)
})
}
/** ********************** 连接到 Git主机拷贝文件到指定路径 ************* **/
function deployToGit(connection){
function deployToGit (connection) {
const pathFn = require('path')
const fs = require('hexo-fs')
const chalk = require('chalk')
@ -192,7 +253,7 @@ function deployToGit(connection){
const spawn = require('hexo-util/lib/spawn')
const swigHelpers = {
now: function(format) {
now: function (format) {
return moment().format(format)
}
}
@ -200,7 +261,7 @@ function deployToGit(connection){
const rRepoURL = /^(?:(?:git|https?|git\+https|git\+ssh):\/\/)?(?:[^@]+@)?([^\/]+?)[\/:](.+?)\.git$/ // eslint-disable-line no-useless-escape
const rGithubPage = /\.github\.(io|com)$/
function parseRepo(repo) {
function parseRepo (repo) {
const split = repo.split(',')
const url = split.shift()
let branch = split[0]
@ -211,7 +272,9 @@ function deployToGit(connection){
const path = match[2]
if (host === 'github.com') {
branch = rGithubPage.test(path) ? (connection.branch || 'main') : 'gh-pages'
branch = rGithubPage.test(path)
? connection.branch || 'main'
: 'gh-pages'
} else if (host === 'coding.net') {
branch = 'coding-pages'
}
@ -223,25 +286,25 @@ function deployToGit(connection){
}
}
function parseConnection(args) {
function parseConnection (args) {
const repo = args.repo || args.repository
if (!repo) throw new TypeError('repo is required!')
if (typeof repo === 'string') {
const data = parseRepo(repo)
data.branch = args.branch || data.branch
return [data]
}
const result = Object.keys(repo).map(key => {
return parseRepo(repo[key])
})
return result
}
function exec() {
function exec () {
const targetDir = ''
const deployDir = pathFn.join(targetDir, '.deploy_git')
const fromDir = wo.envar.deploy.fromPath
@ -258,15 +321,17 @@ function deployToGit(connection){
if (!connection.repo && !connection.repository) {
let help = ''
help += 'You have to configure the deployment settings in config files or command line first!\n\n'
help +=
'You have to configure the deployment settings in config files or command line first!\n\n'
help += 'Example:\n'
help += ' node deploy.js -t git -r https://github.com/OWNER/OWNER.github.io -b main -f ./dist'
help +=
' node deploy.js -t git -r https://github.com/OWNER/OWNER.github.io -b main -f ./dist'
console.log(help)
return
}
function git(...connection) {
function git (...connection) {
return spawn('git', connection, {
cwd: deployDir,
verbose: verbose,
@ -274,114 +339,146 @@ function deployToGit(connection){
})
}
function setup() {
function setup () {
const userName = wo.envar.deploy.gitname || ''
const userEmail = wo.envar.deploy.gitemail || ''
// Create a placeholder for the first commit
return fs.writeFile(pathFn.join(deployDir, 'placeholder'), '').then(() => {
return git('init')
}).then(() => {
return userName && git('config', 'user.name', userName)
}).then(() => {
return userEmail && git('config', 'user.email', userEmail)
}).then(() => {
return git('add', '-A')
}).then(() => {
return git('commit', '-m', 'First commit')
})
}
function push(repo) {
return git('add', '-A').then(() => {
return git('commit', '-m', message).catch(() => {
// Do nothing. It's OK if nothing to commit.
return fs
.writeFile(pathFn.join(deployDir, 'placeholder'), '')
.then(() => {
return git('init')
})
.then(() => {
return userName && git('config', 'user.name', userName)
})
.then(() => {
return userEmail && git('config', 'user.email', userEmail)
})
.then(() => {
return git('add', '-A')
})
.then(() => {
return git('commit', '-m', 'First commit')
})
}).then(() => {
return git('push', '-u', repo.url, 'HEAD:' + repo.branch, '--force')
}).then(()=>{
console.info(`😊😊😊 Successfully deployed [${wo.envar.deploy.fromPath}] to [${connection.repo}#${connection.branch}] 😊😊😊`)
if (connection.url){
console.info(`😊😊😊 ${connection.url} 😊😊😊`)
}
}).catch((err)=>{
console.error(`🤷‍♀️🤷‍♀️🤷‍♀️ Failed deploy [${wo.envar.deploy.fromPath}] to [${connection.repo}#${connection.branch}] 🤷‍♀️🤷‍♀️🤷‍♀️`)
process.exit(1)
})
}
return fs.exists(deployDir).then(function(exist) {
if (exist) return
function push (repo) {
return git('add', '-A')
.then(() => {
return git('commit', '-m', message).catch(() => {
// Do nothing. It's OK if nothing to commit.
})
})
.then(() => {
return git('push', '-u', repo.url, 'HEAD:' + repo.branch, '--force')
})
.then(() => {
console.info(
`😊😊😊 Successfully deployed [${wo.envar.deploy.fromPath}] to [${connection.repo}#${connection.branch}] 😊😊😊`
)
if (connection.url) {
console.info(`😊😊😊 ${connection.url} 😊😊😊`)
}
})
.catch(err => {
console.error(
`🤷‍♀️🤷‍♀️🤷‍♀️ Failed deploy [${wo.envar.deploy.fromPath}] to [${connection.repo}#${connection.branch}] 🤷‍♀️🤷‍♀️🤷‍♀️`
)
process.exit(1)
})
}
// log.info('Setting up Git deployment...')
return setup()
}).then(() => {
// log.info('Clearing .deploy_git folder...')
return fs.emptyDir(deployDir)
}).then(() => {
const opts = {}
// log.info('Copying files from local folder...')
if (typeof ignoreHidden === 'object') {
opts.ignoreHidden = ignoreHidden.public
} else {
opts.ignoreHidden = ignoreHidden
}
return fs
.exists(deployDir)
.then(function (exist) {
if (exist) return
if (typeof ignorePattern === 'string') {
opts.ignorePattern = new RegExp(ignorePattern)
} else if (typeof ignorePattern === 'object' && Reflect.apply(Object.prototype.hasOwnProperty, ignorePattern, ['public'])) {
opts.ignorePattern = new RegExp(ignorePattern.public)
}
return fs.copyDir(fromDir, deployDir, opts)
}).then(() => {
// log.info('Copying files from extend dirs...')
if (!extendDirs) {
return
}
if (typeof extendDirs === 'string') {
extendDirs = [extendDirs]
}
const mapFn = function(dir) {
// log.info('Setting up Git deployment...')
return setup()
})
.then(() => {
// log.info('Clearing .deploy_git folder...')
return fs.emptyDir(deployDir)
})
.then(() => {
const opts = {}
const extendPath = pathFn.join(targetDir, dir)
const extendDist = pathFn.join(deployDir, dir)
// log.info('Copying files from local folder...')
if (typeof ignoreHidden === 'object') {
opts.ignoreHidden = ignoreHidden[dir]
opts.ignoreHidden = ignoreHidden.public
} else {
opts.ignoreHidden = ignoreHidden
}
if (typeof ignorePattern === 'string') {
opts.ignorePattern = new RegExp(ignorePattern)
} else if (typeof ignorePattern === 'object' && Reflect.apply(Object.prototype.hasOwnProperty, ignorePattern, [dir])) {
opts.ignorePattern = new RegExp(ignorePattern[dir])
} else if (
typeof ignorePattern === 'object' &&
Reflect.apply(Object.prototype.hasOwnProperty, ignorePattern, [
'public'
])
) {
opts.ignorePattern = new RegExp(ignorePattern.public)
}
return fs.copyDir(extendPath, extendDist, opts)
}
return Promise.map(extendDirs, mapFn, {
concurrency: 2
return fs.copyDir(fromDir, deployDir, opts)
})
.then(() => {
// log.info('Copying files from extend dirs...')
if (!extendDirs) {
return
}
if (typeof extendDirs === 'string') {
extendDirs = [extendDirs]
}
const mapFn = function (dir) {
const opts = {}
const extendPath = pathFn.join(targetDir, dir)
const extendDist = pathFn.join(deployDir, dir)
if (typeof ignoreHidden === 'object') {
opts.ignoreHidden = ignoreHidden[dir]
} else {
opts.ignoreHidden = ignoreHidden
}
if (typeof ignorePattern === 'string') {
opts.ignorePattern = new RegExp(ignorePattern)
} else if (
typeof ignorePattern === 'object' &&
Reflect.apply(Object.prototype.hasOwnProperty, ignorePattern, [dir])
) {
opts.ignorePattern = new RegExp(ignorePattern[dir])
}
return fs.copyDir(extendPath, extendDist, opts)
}
return Promise.map(extendDirs, mapFn, {
concurrency: 2
})
})
.then(() => {
return parseConnection(connection)
})
.each(function (repo) {
console.log('########## repo ###########')
console.log(repo)
return push(repo)
})
}).then(() => {
return parseConnection(connection)
}).each(function(repo) {
console.log('########## repo ###########')
console.log(repo)
return push(repo)
})
} // end of function exec
function commitMessage(connection) {
const message = connection.m || connection.msg || connection.message || 'Site updated: {{ now(\'YYYY-MM-DD HH:mm:ss\') }}'
function commitMessage (connection) {
const message =
connection.m ||
connection.msg ||
connection.message ||
"Site updated: {{ now('YYYY-MM-DD HH:mm:ss') }}"
return swig.compile(message)(swigHelpers)
}
exec()
}
}