deploy自动部署

deploy.config.js

/*
  deploy.config.js说明:
  ssh: 连接服务器用户信息
  targetDir: 需要压缩的文件目录(启用本地压缩后生效)
  openCompress: 关闭后,将跳过本地文件压缩,直接上传同级目录下指定文件
  openBackUp: 开启后,若远端存在相同目录,则会修改原始目录名称,不会直接覆盖
  deployDir: 指定远端部署地址
  releaseDir: 指定远端部署地址下的发布目录名称
*/

const config = [
  {
    name: '东风浩荡发鬼地方',
    ssh: {
      host: '47.93.231.96',
      port: 22,
      username: 'yonghuming',
      password: 'mima',
      // privateKey: 'E:/id_rsa', // ssh私钥(不使用此方法时请勿填写, 注释即可)
      // passphrase: '123456' // ssh私钥对应解密密码(不存在设为''即可)
    },
    targetDir: './dist', // 目标压缩目录(可使用相对地址)
    openCompress: true, // 是否开启本地压缩
    openBackUp: true, // 是否开启远端备份
    deployDir: '/home/guixiang/unified_platform/', // 远端目录
    releaseDir: 'dist' // 发布目录
  },
  {
    name: '名称',
    ssh: {
      host: '139.224.27.169',
      port: 22,
      username: 'root',
      password: 'shanjian@2019',
    },
    targetDir: './dist', // 目标压缩目录(可使用相对地址)
    openCompress: true, // 是否开启本地压缩
    openBackUp: true, // 是否开启远端备份
    deployDir: '/home/shanjian/unified_platform/', // 远端目录
    releaseDir: 'dist' // 发布目录
  }
]

module.exports = config

deploy/core/compressFile.js

const fs = require('fs')
const archiver = require('archiver')

function compressFile (targetDir, localFile, releaseDir) {
  console.log(targetDir, localFile, releaseDir)
  return new Promise((resolve, reject) => {
    console.log('1-正在压缩文件...')
    const output = fs.createWriteStream(localFile) // 创建文件写入流
    const archive = archiver('zip', {
      zlib: { level: 9 } // 设置压缩等级
    })
    output.on('close', () => {
      resolve(
        console.log('2-压缩完成!共计 ' + (archive.pointer() / 1024 / 1024).toFixed(3) + 'MB')
      )
    }).on('error', (err) => {
      reject(console.error('压缩失败', err))
    })
    archive.pipe(output) // 管道存档数据到文件
    archive.directory(targetDir, releaseDir) // 存储目标文件并重命名
    archive.finalize() // 完成文件追加 确保写入流完成
  })
}

module.exports = compressFile

deploy/core/deleteFile.js

const fs = require('fs')

function deleteFile (path) {
  fs.unlink(path, (err) => {
    if (err) throw err
    console.log('successfully deleted')
  })
}

module.exports = deleteFile

deploy/core/handleCommand.js

function runCommand (ssh, command, path) {
  return new Promise((resolve, reject) => {
    ssh.execCommand(command, {
      cwd: path
    }).then((res) => {
      if (res.stderr) {
        reject(console.error('命令执行发生错误:' + res.stderr))
        process.exit()
      } else {
        resolve(console.log(command + ' 执行完成!'))
      }
    })
  })
}

module.exports = runCommand

deploy/core/helper.js


```bash
const inquirer = require('inquirer')

const selectTip = 'project name:'
const options = [
  {
    type: 'list',
    name: selectTip,
    message: 'Which project do you want to deploy?',
    choices: []
    // new inquirer.Separator() // 分割线
  }
]

// 显示选择提示窗
function showHelper (config) {
  return new Promise((resolve, reject) => {
    initHelper(config) // 初始化helper
    inquirer.prompt(options).then(answers => {
      resolve({ value: findInfoByName(config, answers[selectTip]) }) // 查找所选配置项
    }).catch((err) => {
      reject(console.error(' helper显示或选择出错!', err))
    })
  })
}

// 初始化helper
function initHelper (config) {
  for (const item of config) {
    options[0].choices.push(item.name)
  }
  console.log('正在检查全局配置信息...')
  // 检查是否存在相同name
  if (new Set(options[0].choices).size !== options[0].choices.length) {
    console.error('请检查配置信息,存在相同name!')
    process.exit()
  }
}

// 查找符合条件的配置项
function findInfoByName (config, name) {
  for (const item of config) {
    if (item.name === name) {
      return item
    }
  }
}

module.exports = showHelper

deploy/core/ssh.js

const NodeSSH = require('node-ssh')
const ssh = new NodeSSH()

// 连接服务器
function connectServe (sshInfo) {
  return new Promise((resolve, reject) => {
    ssh.connect({ ...sshInfo }).then(() => {
      resolve(console.log('3-' + sshInfo.host + ' 连接成功'))
    }).catch((err) => {
      reject(console.error('3-' + sshInfo.host + ' 连接失败', err))
    })
  })
}

module.exports = { ssh, connectServe }
const NodeSSH = require('node-ssh')
const ssh = new NodeSSH()

// 连接服务器
function connectServe (sshInfo) {
  return new Promise((resolve, reject) => {
    ssh.connect({ ...sshInfo }).then(() => {
      resolve(console.log('3-' + sshInfo.host + ' 连接成功'))
    }).catch((err) => {
      reject(console.error('3-' + sshInfo.host + ' 连接失败', err))
    })
  })
}

module.exports = { ssh, connectServe }

deploy/core/uploadFile.js

const runCommand = require('./handleCommand')
const getCurrentTime = require('./handleTime')

// 文件上传(ssh对象、配置信息、本地待上传文件)
async function uploadFile (ssh, config, targetFile, localFile) {
  return new Promise((resolve, reject) => {
    console.log('4-开始文件上传')
    handleSourceFile(ssh, config)
    ssh.putFile(localFile, config.deployDir + targetFile).then(async () => {
      resolve(console.log('5-文件上传完成'))
    }, (err) => {
      reject(console.error('5-上传失败!', err))
    })
  })
}

// 处理源文件(ssh对象、配置信息)
async function handleSourceFile (ssh, config) {
  if (config.openBackUp) {
    console.log('已开启远端备份!')
    await runCommand(
      ssh,
      `
      if [ -d ${config.releaseDir} ];
      then mv ${config.releaseDir} ${config.releaseDir}_${getCurrentTime()}
      fi
      `,
      config.deployDir)
  } else {
    console.log('提醒:未开启远端备份!')
    await runCommand(
      ssh,
      `
      if [ -d ${config.releaseDir} ];
      then mv ${config.releaseDir} /tmp/${config.releaseDir}_${getCurrentTime()}
      fi
      `,
      config.deployDir)
  }
}

module.exports = uploadFile

deploy/index.js

const config = require('../deploy.config.js')
const helper = require('./core/helper')
const compressFile = require('./core/compressFile')
const sshServer = require('./core/ssh')
const uploadFile = require('./core/uploadFile')
const runCommand = require('./core/handleCommand')
const deleteFile = require('./core/deleteFile')

// 主程序(可单独执行)
async function main () {
  try {
    const SELECT_CONFIG = (await helper(config)).value // 所选部署项目的配置信息
    console.log('您选择了部署 ' + SELECT_CONFIG.name)
    const targetFile = `${SELECT_CONFIG.releaseDir}.zip` // 本地压缩文件
    const localFile = `${__dirname}/${targetFile}` // 待上传本地文件
    SELECT_CONFIG.openCompress ? await compressFile(SELECT_CONFIG.targetDir, localFile, SELECT_CONFIG.releaseDir) : '' //压缩
    await sshServer.connectServe(SELECT_CONFIG.ssh) // 连接
    await uploadFile(sshServer.ssh, SELECT_CONFIG, targetFile, localFile) // 上传
    await runCommand(sshServer.ssh, 'unzip ' + targetFile, SELECT_CONFIG.deployDir) // 解压
    await runCommand(sshServer.ssh, 'rm -f ' + targetFile, SELECT_CONFIG.deployDir) // 删除
    deleteFile(localFile) // 删除本地压缩文件
  } catch (err) {
    console.log('部署过程出现错误!', err)
  } finally {
    process.exit()
  }
}

// run main
main()

package.json

`{
  "name": "smart-elevator-admin",
  "name": "unified-platform",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "build:pro": "vue-cli-service build --mode production",
    "lint": "npm run lint:code && npm run lint:style",
    "lint:code": "vue-cli-service lint",
    "lint:style": "vue-cli-service lint:style"
    "lint:style": "vue-cli-service lint:style",
    "deploy:dev": "npm run build:dev && node ./deploy/index.js",
    "deploy:pro": "npm run build:pro && node ./deploy/index.js"
  },
  "husky": {
    "hooks": {
    "@vue/cli-plugin-vuex": "^4.2.3",
    "@vue/cli-service": "^4.2.3",
    "@vue/eslint-config-standard": "^5.1.2",
    "archiver": "^3.1.1",
    "babel-eslint": "^10.1.0",
    "babel-plugin-import": "^1.13.0",
    "commitizen": "^4.0.3",
    "eslint-plugin-standard": "^4.0.1",
    "eslint-plugin-vue": "^6.2.2",
    "husky": "^4.2.3",
    "inquirer": "^7.1.0",
    "less": "^3.11.1",
    "less-loader": "^5.0.0",
    "lint-staged": "^10.0.8",
    "node-ssh": "^8.0.0",
    "stylelint": "^13.2.1",
    "stylelint-config-rational-order": "^0.1.2",
    "stylelint-config-standard": "^20.0.0",

public/index.html

</head>
<body>
<noscript>
  <strong>We're sorry but smart-elevator-admin doesn't work properly without JavaScript enabled. Please enable it to
  <strong>We're sorry but unified-platform doesn't work properly without JavaScript enabled. Please enable it to
    continue.</strong>
</noscript>
<div id="app"></div>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值