1 | const fs = require('fs-extra')
|
2 | const path = require('path')
|
3 | const semver = require('semver')
|
4 | const chalk = require('chalk')
|
5 | const inquirer = require('inquirer')
|
6 | const { exec } = require('child_process')
|
7 |
|
8 | const consoleLogConfigPath = path.resolve(__dirname, '../config/config.console.json')
|
9 | const consoleLog = require(consoleLogConfigPath)
|
10 |
|
11 |
|
12 | const { log } = console
|
13 | const getLogConfig = () => {
|
14 | const logger = {}
|
15 | const { color } = consoleLog
|
16 |
|
17 | Object.keys(color).map(key => {
|
18 | logger[key] = (msg, val = '') => log(chalk.hex(color[key])(msg, val))
|
19 | })
|
20 |
|
21 | return logger
|
22 | }
|
23 |
|
24 | const { error, info, success, warn } = getLogConfig()
|
25 |
|
26 | const uniqueDirname = (dir, prefix) => {
|
27 | let rnd = `${(prefix || '')}${parseInt(Math.random() * 10000).toString()}`
|
28 |
|
29 | try {
|
30 | const files = fs.readdirSync(dir)
|
31 |
|
32 | while (files.indexOf(rnd) !== -1) {
|
33 | rnd = `${(prefix || '')}${parseInt(Math.random() * 10000).toString()}`
|
34 | }
|
35 | } catch (e) {
|
36 | console.error(e)
|
37 | }
|
38 |
|
39 | return path.join(dir, rnd)
|
40 | }
|
41 |
|
42 | const camelize = (str) => {
|
43 | return str.replace(/-(\w)/g, (_, c) => c ? c.toUpperCase() : '')
|
44 | }
|
45 |
|
46 |
|
47 |
|
48 | const cleanArgs = (cmd) => {
|
49 | const args = {}
|
50 |
|
51 | cmd.options.forEach(o => {
|
52 | const key = camelize(o.long.replace(/^--/, ''))
|
53 |
|
54 |
|
55 | if (typeof cmd[key] !== 'function' && typeof cmd[key] !== 'undefined') {
|
56 | args[key] = cmd[key]
|
57 | }
|
58 | })
|
59 |
|
60 | return args
|
61 | }
|
62 |
|
63 | const checkNodeVersion = (wanted, id) => {
|
64 | if (!semver.satisfies(process.version, wanted)) {
|
65 | console.error(
|
66 | `You are using Node ${process.version}, but this version of ${id} requires Node ${wanted}.
|
67 | \nPlease upgrade your Node version.\n`
|
68 | )
|
69 |
|
70 | process.exit(1)
|
71 | }
|
72 | }
|
73 |
|
74 | const pwdValidator = value => {
|
75 | if (!value) {
|
76 | return '请输入你的SSH登录密码'
|
77 | }
|
78 |
|
79 | if (/[\u4e00-\u9fa5]/gm.test(value)) {
|
80 | return '你确定你的SSH登录密码里面有中文字符?😱😱😱'
|
81 | }
|
82 |
|
83 | return true
|
84 | }
|
85 |
|
86 | const getPwd = async () => {
|
87 | const answers = await inquirer.prompt([{
|
88 | type: 'password',
|
89 | message: '请输入ssh登录密码',
|
90 | name: 'pwd',
|
91 | validate: pwdValidator,
|
92 | }])
|
93 |
|
94 | info('\n✅ 密码get✔︎,放心我不告诉别人🤣\n')
|
95 |
|
96 | return answers.pwd
|
97 | }
|
98 |
|
99 | const getSecret = async () => {
|
100 | const answers = await inquirer.prompt([{
|
101 | type: 'password',
|
102 | message: '请输入OSS服务器的accessKeySecret',
|
103 | name: 'accessKeySecret',
|
104 | }])
|
105 |
|
106 | info('\n✅ get✔︎,放心我不告诉别人🤣\n')
|
107 |
|
108 | return answers.accessKeySecret
|
109 | }
|
110 |
|
111 | const paramsValidator = {
|
112 | web: {
|
113 | msg: '请设置web服务器(希望项目部署到的服务器地址)e.g. deploy-set -k web -v 88.88.88.88',
|
114 | },
|
115 | dir: {
|
116 | msg: '请设置web服务器部署项目的目录,e.g. deploy-set -k dir -v /www/proj/',
|
117 | },
|
118 | user: {
|
119 | msg: '请设置ssh登录服务器的用户名,如root',
|
120 | },
|
121 | isNeedBuild: {
|
122 | msg: '请设置项目是否需要打包,如需打包必须传入打包命令',
|
123 | },
|
124 | buildScript: {
|
125 | msg: '请设置项目需要打包情况下执行的打包命令,传入build,则执行npm run build',
|
126 | },
|
127 | distDir: {
|
128 | msg: '请设置项目存放打包后文件的目录',
|
129 | },
|
130 | }
|
131 |
|
132 | const paramChecker = (config) => {
|
133 |
|
134 | const paramError = Object.keys(paramsValidator).find(key => config[key] === undefined)
|
135 |
|
136 | if (paramError) {
|
137 | error(`配置项缺失:${paramsValidator[paramError].msg}`)
|
138 |
|
139 | process.exit(1)
|
140 | }
|
141 | }
|
142 |
|
143 | const shell = (order, option = {}) => {
|
144 | return new Promise((reslove, reject) => {
|
145 | exec(order, option, (err, stdout) => {
|
146 | if (err) {
|
147 | reject(err)
|
148 | } else {
|
149 | reslove(stdout)
|
150 | }
|
151 | })
|
152 | })
|
153 | }
|
154 |
|
155 | const getProjectConfig = (scheme) => {
|
156 | const projectDir = process.cwd()
|
157 |
|
158 | const projectPackageInfoPath = path.resolve(projectDir, './package.json')
|
159 | const projectConfigMapPath = path.resolve(projectDir, './deploy.config.js')
|
160 |
|
161 | if (!fs.existsSync(projectConfigMapPath)) {
|
162 | error(`\n❌ 请在项目根目录新建“deploy.config.js”文件,用做该项目部署使用的配置\n`)
|
163 |
|
164 | process.exit(1)
|
165 | }
|
166 |
|
167 | delete require.cache[require.resolve(projectPackageInfoPath)]
|
168 | delete require.cache[require.resolve(projectConfigMapPath)]
|
169 |
|
170 | const projectConfigMap = require(projectConfigMapPath)
|
171 | const projectConfig = projectConfigMap[scheme]
|
172 | const { name } = require(projectPackageInfoPath)
|
173 |
|
174 | if (!name) {
|
175 | error(`\n❌ name字段缺失,请检查项目package.json文件,确保存在name字段\n`)
|
176 |
|
177 | process.exit(1)
|
178 | }
|
179 |
|
180 |
|
181 | if (!projectConfig) {
|
182 | error(`\n❌ 部署方案${scheme}未配置\n`)
|
183 |
|
184 | process.exit(1)
|
185 | }
|
186 |
|
187 | return {
|
188 | ...projectConfig,
|
189 | projectDir,
|
190 | name,
|
191 | }
|
192 | }
|
193 |
|
194 | module.exports = {
|
195 | cleanArgs,
|
196 | checkNodeVersion,
|
197 | uniqueDirname,
|
198 | error,
|
199 | info,
|
200 | success,
|
201 | warn,
|
202 | getPwd,
|
203 | getSecret,
|
204 | paramChecker,
|
205 | shell,
|
206 | getProjectConfig,
|
207 | }
|