| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- /* eslint-disable new-cap */
- const path = require('path')
- const chalk = require('chalk') // 命令行颜色
- const ora = require('ora') // 加载流程动画
- const shell = require('shelljs') // 执行shell命令
- const { NodeSSH } = require('node-ssh') // ssh连接服务器
- const inquirer = require('inquirer') // 命令行交互
- const zipFile = require('compressing')// 压缩zip
- const spinner_style = require('./spinner_style') // 加载动画样式
- const CONFIG = require('./config') // 配置
- const SSH = new NodeSSH()
- let config // 用于保存 inquirer 命令行交互后选择正式|测试版的配置
- // logs
- const defaultLog = log => console.log(chalk.blue(`---------------- ${log} ----------------`))
- const errorLog = log => console.log(chalk.red(`---------------- ${log} ----------------`))
- const successLog = log => console.log(chalk.green(`---------------- ${log} ----------------`))
- // 文件夹目录
- const distDir = path.resolve(__dirname, '../dist') // 待打包
- const distZipPath = path.resolve(__dirname, '../dist.zip')
- // 项目打包代码 yarn build
- const compileDist = async () => {
- const loading = ora(defaultLog('project build start')).start()
- loading.spinner = spinner_style.arrow4
- shell.cd(path.resolve(__dirname, '../'))
- const res = await shell.exec('yarn build') // 执行shell 打包命令
- loading.stop()
- if (res.code === 0) {
- successLog('project build success!')
- } else {
- errorLog('project build error, please try again!')
- process.exit() // 退出流程
- }
- }
- // 压缩代码
- const zipDist = async () => {
- defaultLog('project zip start')
- try {
- await zipFile.zip.compressDir(distDir, distZipPath)
- successLog('project zip success!')
- } catch (error) {
- errorLog(error)
- errorLog('project zip error, exit process!')
- process.exit() // 退出流程
- }
- }
- // 连接服务器
- const connectSSH = async () => {
- const loading = ora(defaultLog('connecting server')).start()
- loading.spinner = spinner_style.arrow4
- try {
- await SSH.connect({
- host: config.SERVER_PATH,
- username: config.SSH_USER,
- password: config.PASSWORD,
- })
- successLog('SSH connect success!')
- } catch (error) {
- errorLog(error)
- errorLog('SSH connect error!')
- process.exit() // 退出流程
- }
- loading.stop()
- }
- // 线上执行命令
- /**
- *
- * @param {String} command 命令操作 如 ls
- */
- const runCommand = async (command) => {
- const result = await SSH.exec(command, [], { cwd: config.PATH })
- defaultLog(result)
- }
- // 清空线上目标目录里的旧文件
- const clearOldFile = async () => {
- const commands = ['ls', 'rm -rf *']
- await Promise.all(commands.map(async (it) => {
- return await runCommand(it)
- }))
- }
- // 传送zip文件到服务器
- const uploadZipBySSH = async () => {
- // 连接ssh
- await connectSSH()
- // 线上目标文件清空
- await clearOldFile()
- const loading = ora(defaultLog('prepare to upload files')).start()
- loading.spinner = spinner_style.arrow4
- try {
- await SSH.putFiles([{ local: distZipPath, remote: config.PATH + '/dist.zip' }]) // local 本地 ; remote 服务器 ;
- successLog('upload files success!')
- loading.text = 'unzip file'
- await runCommand('unzip ./dist.zip') // 解压
- await runCommand(`rm -rf ${config.PATH}/dist.zip`) // 解压完删除线上压缩包
- // 将目标目录的dist里面文件移出到目标文件
- await runCommand(`mv -f ${config.PATH}/dist/* ${config.PATH}`)
- await runCommand(`rm -rf ${config.PATH}/dist`) // 移出后删除 dist 文件夹
- SSH.dispose() // 断开连接
- } catch (error) {
- errorLog(error)
- errorLog('upload failed!')
- process.exit() // 退出流程
- }
- loading.stop()
- }
- // ------------发布程序---------------
- const runUploadTask = async () => {
- console.log(chalk.yellow('---------> Welcome to MJ 2020 automatic deployment tool <---------'))
- // 打包
- await compileDist()
- // 压缩
- await zipDist()
- // 连接服务器上传文件
- await uploadZipBySSH()
- successLog('Good luck, successful deployment!')
- process.exit()
- }
- // 开始前的配置检查
- /**
- *
- * @param {Object} conf 配置对象
- */
- const checkConfig = (conf) => {
- const checkArr = Object.entries(conf)
- checkArr.map(it => {
- const key = it[0]
- if (key === 'PATH' && conf[key] === '/') { // 上传zip前会清空目标目录内所有文件
- errorLog('PATH cannot be the server root directory!')
- process.exit() // 退出流程
- }
- if (!conf[key]) {
- errorLog(`Configuration ${key} cannot be empty`)
- process.exit() // 退出流程
- }
- })
- }
- // 执行交互后 启动发布程序
- inquirer
- .prompt([{
- type: 'list',
- message: 'Please select publishing environment',
- name: 'env',
- choices: [{
- name: 'development',
- value: 'development',
- }, {
- name: 'production',
- value: 'production',
- }],
- }])
- .then(answers => {
- config = CONFIG[answers.env]
- checkConfig(config) // 检查
- runUploadTask() // 发布
- })
|