格式化

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

237
deploy.js
View File

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