-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdeploy.js
More file actions
328 lines (294 loc) · 9.23 KB
/
Copy pathdeploy.js
File metadata and controls
328 lines (294 loc) · 9.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
#!/usr/bin/env node
'use strict';
const EasyFtp = require('easy-ftp')
const fs = require('fs')
const util = require('util')
const exec = util.promisify(require('child_process').exec)
const workingDir = process.cwd()
const branchNameF = require('current-git-branch')
const repoNameF = require('git-repo-name')
const readlineSync = require('readline-sync')
const jsonfile = require('jsonfile')
const glob = require("glob")
const eventToPromise = require('event-to-promise')
const md5File = require('md5-file')
const version = require('./package.json').version
//console.log(__dirname)
//return
let branchName
try {
branchName = branchNameF()
} catch(err) {
}
let repoName
if (branchName) {
try {
repoName = repoNameF.sync()
} catch(err) {
}
}
const options = getArgs()
if (options.sample) {
fs.copyFileSync(__dirname + '/deploy.sample.conf.json', workingDir + '/deploy.sample.conf.json')
console.log("\n\nSample file copied. Rename it to deploy.conf.json to use it.\n")
exit()
}
const configPath = options.deployConfigFile ? workingDir + '/' + options.deployConfigFile : workingDir + '/deploy.conf.json'
const configPathPw = workingDir + '/deploy.pw.conf.json'
const pathToDownloadedCache = workingDir + '/deploy.cache.json'
let configObj
let configPwObj
let uploadedFiles = 0
try {
//configObj = require(configPath)
configObj = jsonfile.readFileSync(configPath)
} catch(err) {
console.error("\n\n\x1b[31mCannot find '"+configPath+"'. Please visit https://www.npmjs.com/package/deploydo and read the documentation. Type 'deploydo sample' to get a sample file.")
exit()
}
let files = []
let uploadFiles = []
const ftp = new EasyFtp()
ftp.on('open', () => {
})
ftp.on('error', (err) => {
if (err) console.log(err)
})
ftp.on('upload', (i) => {
uploadedFiles++
config.verbose && console.log("\x1b[32m"+i)
})
ftp.on('uploading', (i) => {
})
ftp.on('close', () => {
//console.log('close')
})
if (!configObj) {
console.error("\n\x1b[31mCouldn't find config. Please read the documentation: https://www.npmjs.com/package/deploydo \n")
}
let config
if (options.env) {
if (configObj[options.env]) {
config = configObj[options.env]
} else {
console.error("\n\n\x1b[31mCouldn't find config environment '"+configObj[options.env]+"'\n\n")
exit()
}
} else {
options.env = 'default'
if (configObj.default) {
config = configObj.default
} else {
console.error("\n\n\x1b[31mCouldn't find default config environment. Please read the documentation: https://www.npmjs.com/package/deploydo \n\n")
exit()
}
}
handlePassword()
handleGitignore()
async function run() {
try {
let really
if (branchName && repoName) {
really = readlineSync.question('\n\n\x1b[36mPlease check if everything is correct:\n\nRepository: ' + repoName + '\ncurrent branch: ' + branchName + '\nHost: ' + config.host + '\nlocal Folder: ' + config.sourcePath + '\nremote Folder: ' + config.remotePath + '\n\nShould I start the deployment? (y/n) ')
} else {
really = readlineSync.question('\n\n\x1b[36mPlease check if everything is correct:\n\nHost: ' + config.host + '\nlocal Folder: ' + config.sourcePath + '\nremote Folder: ' + config.remotePath + '\n\nShould I start the deployment? (y/n) ')
}
if (really !== 'y' && really !== 'Y') {
console.log("\x1b[36mDeployment cancelled by user")
exit()
}
console.log('\n\x1b[32m', '=== deployment script started - deploydo ' + version +' - ===\n')
if (config.buildCommand) {
console.log('\n\x1b[32m', '\nBuilding App for production...\n')
var child = await exec(config.buildCommand)
console.log(child.stdout)
console.log('\n\x1b[32m', '\nBuilding done!\n')
}
console.log('\nConnecting to server...\n')
const conf = {
"host": config.host,
"port": config.port,
"username": config.user,
"password": config.pass,
"type": config.type
}
let f = glob.sync('**', {cwd: workingDir + config.sourcePath, ignore: config.ignore || []})
for (let file of f) {
let lPath = '.' + config.sourcePath + '/' + file
/*
dont upload directories, because all child files will be uploaded; but all child files will be uploaded again; thats unnecessary overhead; additionally the ignore filter wouldn't work
*/
if (!(fs.existsSync(lPath) && fs.lstatSync(lPath).isDirectory())) {
uploadFiles.push({
local: lPath,
remote: config.remotePath + '/' + file
})
}
}
//console.log(uploadFiles)
ftp.connect(conf)
await eventToPromise(ftp, 'open')
if (config.useCache) await handleCache()
//console.log(uploadFiles)
handleUpload(conf)
return
} catch(err) {
console.log(err)
return
}
}
async function handleCache() {
let cacheExists = await downloadCache()
let cacheArray = []
let fileExists
if (cacheExists) {
try {
cacheArray = jsonfile.readFileSync(pathToDownloadedCache)
fileExists = true
} catch(err) {
fileExists = false
cacheArray = []
}
}
for (let f of uploadFiles) {
const hash = md5File.sync(f.local)
//console.log(f.local, hash)
let findInCache = cacheArray.find((i) => i.fileName === f.local)
//if file found in cache array
if (findInCache) {
//check if md5 is the same
//console.log("found in cache")
if (findInCache.md5 === hash) {
//console.log("same md5")
//flag to remove
f.removeFromList = true
} else {
//refresh hash
findInCache.md5 = hash
}
} else {
//add to cache
cacheArray.push({
fileName: f.local,
md5: hash
})
}
}
jsonfile.writeFileSync(pathToDownloadedCache, cacheArray)
uploadFiles.push({
local: pathToDownloadedCache,
remote: config.remotePath + '/deploy.cache.json'
})
uploadFiles = uploadFiles.filter((i) => !i.removeFromList)
}
function downloadCache() {
return new Promise((resolve, reject) => {
ftp.download(config.remotePath + "/deploy.cache.json", pathToDownloadedCache, function(err){
if (err) {
//console.log(err)
resolve(false)
} else {
resolve(true)
}
})
})
}
function handleUpload(conf) {
console.log('\nConnection to server established\n')
console.log("\n\x1b[32mUploading...\n")
ftp.upload(uploadFiles, function (err) {
if (err) {
console.error(err)
exit()
}
console.log("\n\x1b[32m"+uploadedFiles+" files have been uploaded.\n")
console.log("\n\x1b[32mDeployment Done!\n")
console.log('\x1b[0m')
ftp.close()
})
}
function getArgs() {
const args = {}
process.argv
.slice(2, process.argv.length)
.forEach(arg => {
// long arg
if (arg.slice(0, 2) === '--') {
const longArg = arg.split('=')
const longArgFlag = longArg[0].slice(2, longArg[0].length)
const longArgValue = longArg.length > 1 ? longArg[1] : true
args[longArgFlag] = longArgValue
}
// flags
else if (arg[0] === '-') {
const flags = arg.slice(1, arg.length).split('')
flags.forEach(flag => {
args[flag] = true
})
}
})
return args
}
function handlePassword() {
//check if pw file exists
let fileExists = false
let envPasswordExists = false
try {
configPwObj = jsonfile.readFileSync(configPathPw)
fileExists = true
} catch(err) {
fileExists = false
}
if (!configPwObj) configPwObj = {}
//if yes, check if pw for environment has been set
if (fileExists) {
if (configPwObj[options.env]) {
envPasswordExists = true
config.pass = configPwObj[options.env]
}
else envPasswordExists = false
}
//if not, ask user for pw and if the pw should be saved
if (!envPasswordExists) {
let pass = readlineSync.question('\n\n\x1b[36mPlease enter password: ', {hideEchoBack: true, mask: '*'})
config.pass = pass
let savePass = readlineSync.question('\n\n\x1b[36mShall I save the password for you in an extra file (deploy.pw.conf.json) (y/n) ')
//if yes, save it
if (savePass == 'y' || savePass == 'Y') {
if (!fileExists) {
fs.writeFileSync(configPathPw, '{}')
}
configPwObj[options.env] = config.pass
jsonfile.writeFileSync(configPathPw, configPwObj)
}
}
}
function handleGitignore() {
let gitignoreExists = false
let foundEntry = false
let gitignoreFilePath = workingDir + '/.gitignore'
if (fs.existsSync(gitignoreFilePath)) {
gitignoreExists = true
}
let ignoreContent = ''
if (!gitignoreExists) {
fs.writeFileSync(gitignoreFilePath, 'deploy.pw.conf.json')
} else {
ignoreContent = fs.readFileSync(workingDir + '/.gitignore', 'utf8')
foundEntry = ignoreContent.indexOf('deploy.pw.conf.json')
if (foundEntry === -1) foundEntry = false
else foundEntry = true
}
if (!foundEntry) {
let shallWrite = readlineSync.question('\n\n\x1b[36mThere is a deploy.pw.conf.json in your working directory which is currently not in your .gitignore or there is no .gitignore file. Should I take care and add this file to .gitignore (y/n) ')
if (shallWrite == 'y' || shallWrite == 'Y') {
let content = 'deploy.pw.conf.json\n' + ignoreContent
fs.writeFileSync(workingDir + '/.gitignore', content, 'utf8')
}
}
}
function exit() {
console.log('\x1b[0m')
process.exit()
}
run()