-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathpublisher.js
143 lines (107 loc) · 3.54 KB
/
publisher.js
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
'use strict'
const ServerCodeModel = require('./model')
const logger = require('../util/logger')
const path = require('path')
const fs = require('fs')
const file = require('../util/file')
const cliUtils = require('../cli/utils')
const bytesUtils = require('../util/bytes')
const JSZip = require('jszip')
const ApiServerService = require('./services/api-server')
const PACKAGE_FILE = 'package.json'
const BASE_PATTERNS = ['**', '!node_modules/**', '!deploy.zip']
const EXCLUDE_MODULES = [
'backendless-coderunner'
]
const publish = async opts => {
const apiServer = new ApiServerService(opts.app, opts.backendless.apiUrl)
function buildModel() {
const model = ServerCodeModel.build(process.cwd(), opts.app.exclude)
if (model.isEmpty() && !opts.allowEmpty) {
throw new Error('Nothing to publish')
}
if (model.errors.length) {
throw new Error('Please resolve Model Errors before deploying to production')
}
return model
}
function zip(model) {
const exclude = (opts.app.exclude || []).map(pattern => '!' + pattern)
const patterns = BASE_PATTERNS.concat(dependencyPatterns()).concat(exclude)
return generateZip(model, patterns, opts.keepZip)
}
async function confirmZipSize(modelZip) {
logger.info(`Generated Zip File size is: ${bytesUtils.formatBytes(modelZip.length)}`)
if (opts.zipSizeConfirmation) {
const confirmMsg = 'Would you like to deploy it? (Y/N)'
const confirmed = await cliUtils.confirmation(confirmMsg)
if (!confirmed) {
process.exit(0)
}
}
}
function publishModel(model, modelZip) {
return apiServer.publish(model, modelZip, opts.deploy.progressInterval)
}
const model = await buildModel()
const modelZip = await zip(model)
await confirmZipSize(modelZip)
return publishModel(model, modelZip)
}
async function generateZip(model, patterns, keep) {
logger.info('Preparing app zip file for deployment..')
logger.debug('File patterns to be included:')
patterns.forEach(pattern => logger.debug(pattern))
const zip = new JSZip()
const expanded = file.expand(patterns)
let files = 0
zip.file('model.json', JSON.stringify(model))
expanded.forEach(item => {
if (fs.statSync(item).isDirectory()) {
zip.folder(item)
} else {
zip.file(item, fs.readFileSync(item))
files++
}
})
logger.info(`${files} files added into deployment archive`)
const result = await zip.generateAsync({ type: 'nodebuffer' })
if (keep) {
fs.writeFileSync('deploy.zip', result)
logger.info(`Deployment archive is saved to ${path.resolve('deploy.zip')}`)
}
return result
}
function dependencyPatterns() {
const pkgFile = path.resolve(PACKAGE_FILE)
const result = []
if (fs.existsSync(pkgFile)) {
addDependencies(result, require(pkgFile))
} else {
logger.info(
"Warning. Working directory doesn't contain package.json file. " +
'CodeRunner is not able to auto include dependencies into deployment'
)
}
return result
}
function addDependencies(out, pkg) {
pkg && pkg.dependencies && Object.keys(pkg.dependencies).reduce(addDependency, out)
}
function addDependency(out, name) {
const pattern = `node_modules/${name}/**`
if (!EXCLUDE_MODULES.includes(name) && !out.includes(pattern)) {
out.push(pattern)
try {
addDependencies(out, require(path.resolve('node_modules', name, PACKAGE_FILE)))
} catch (err) {
// dependency not found at the root level. for npm2 it's ok
}
}
return out
}
module.exports = opts => ({
start() {
return publish(opts)
}
})