@adobe/aio-cli-plugin-app 10.0.3 → 10.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
- package/src/commands/app/add/service.js +11 -2
- package/src/commands/app/init.js +1 -1
- package/src/commands/app/use.js +6 -35
- package/src/lib/import-helper.js +631 -0
- package/src/lib/import.js +35 -614
- package/src/lib/log-forwarding.js +1 -1
package/src/lib/import.js
CHANGED
|
@@ -1,631 +1,52 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
-
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
-
Unless required by applicable law or agreed to in writing, software distributed under
|
|
7
|
-
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
8
|
-
OF ANY KIND, either express or implied. See the License for the specific language
|
|
9
|
-
governing permissions and limitations under the License.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-app:import', { provider: 'debug' })
|
|
13
|
-
const config = require('@adobe/aio-lib-core-config')
|
|
14
|
-
const defaults = require('./defaults')
|
|
15
|
-
const path = require('path')
|
|
16
|
-
const fs = require('fs-extra')
|
|
17
|
-
const inquirer = require('inquirer')
|
|
18
|
-
const yaml = require('js-yaml')
|
|
19
|
-
const hjson = require('hjson')
|
|
20
|
-
const Ajv = require('ajv')
|
|
21
|
-
const { EOL } = require('os')
|
|
22
|
-
|
|
23
|
-
const AIO_FILE = '.aio'
|
|
24
|
-
const ENV_FILE = '.env'
|
|
25
|
-
const AIO_ENV_PREFIX = 'AIO_'
|
|
26
|
-
const AIO_ENV_SEPARATOR = '_'
|
|
27
|
-
const FILE_FORMAT_ENV = 'env'
|
|
28
|
-
const FILE_FORMAT_JSON = 'json'
|
|
29
|
-
const CONSOLE_CONFIG_KEY = 'console'
|
|
30
|
-
|
|
31
|
-
// make sure to prompt to stderr
|
|
32
|
-
// Note: if this get's turned into a lib make sure to call
|
|
33
|
-
// this into an init/constructor as it might create mocking issues in jest
|
|
34
|
-
const prompt = inquirer.createPromptModule({ output: process.stderr })
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Validate the config json
|
|
38
|
-
*
|
|
39
|
-
* @param {object} configJson the json to validate
|
|
40
|
-
* @returns {object} with keys valid (boolean) and errors (object). errors is null if no errors
|
|
41
|
-
*/
|
|
42
|
-
function validateConfig (configJson) {
|
|
43
|
-
/* eslint-disable-next-line node/no-unpublished-require */
|
|
44
|
-
const schema = require('../../schema/config.schema.json')
|
|
45
|
-
const ajv = new Ajv({ allErrors: true })
|
|
46
|
-
const validate = ajv.compile(schema)
|
|
47
|
-
|
|
48
|
-
return { valid: validate(configJson), errors: validate.errors }
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Load a config file
|
|
53
|
-
*
|
|
54
|
-
* @param {string} fileOrBuffer the path to the config file or a Buffer
|
|
55
|
-
* @returns {object} object with properties `value` and `format`
|
|
56
|
-
*/
|
|
57
|
-
function loadConfigFile (fileOrBuffer) {
|
|
58
|
-
let contents
|
|
59
|
-
if (typeof fileOrBuffer === 'string') {
|
|
60
|
-
contents = fs.readFileSync(fileOrBuffer, 'utf-8')
|
|
61
|
-
} else if (Buffer.isBuffer(fileOrBuffer)) {
|
|
62
|
-
contents = fileOrBuffer.toString('utf-8')
|
|
63
|
-
} else {
|
|
64
|
-
contents = ''
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
contents = contents.trim()
|
|
68
|
-
|
|
69
|
-
if (contents) {
|
|
70
|
-
if (contents[0] === '{') {
|
|
71
|
-
try {
|
|
72
|
-
return { values: hjson.parse(contents), format: 'json' }
|
|
73
|
-
} catch (e) {
|
|
74
|
-
throw new Error('Cannot parse json')
|
|
75
|
-
}
|
|
76
|
-
} else {
|
|
77
|
-
try {
|
|
78
|
-
return { values: yaml.load(contents, { json: true }), format: 'yaml' }
|
|
79
|
-
} catch (e) {
|
|
80
|
-
throw new Error('Cannot parse yaml')
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return { values: {}, format: 'json' }
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Load and validate a config file
|
|
89
|
-
*
|
|
90
|
-
* @param {string} fileOrBuffer the path to the config file or a Buffer
|
|
91
|
-
* @returns {object} object with properties `value` and `format`
|
|
92
|
-
*/
|
|
93
|
-
function loadAndValidateConfigFile (fileOrBuffer) {
|
|
94
|
-
const res = loadConfigFile(fileOrBuffer)
|
|
95
|
-
const { valid: configIsValid, errors: configErrors } = validateConfig(res.values)
|
|
96
|
-
if (!configIsValid) {
|
|
97
|
-
const message = `Missing or invalid keys in config: ${JSON.stringify(configErrors, null, 2)}`
|
|
98
|
-
throw new Error(message)
|
|
99
|
-
}
|
|
100
|
-
return res
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Writes default app config to .aio file
|
|
105
|
-
*
|
|
106
|
-
* @param {string} parentDir the parent folder to write the .aio file to
|
|
107
|
-
* @param {object} [flags] flags for file writing
|
|
108
|
-
* @param {boolean} [flags.overwrite=false] set to true to overwrite the existing .env file
|
|
109
|
-
* @param {boolean} [flags.merge=false] set to true to merge in the existing .env file (takes precedence over overwrite)
|
|
110
|
-
* @param {boolean} [flags.interactive=false] set to true to prompt the user for file overwrite
|
|
111
|
-
* @returns {Promise} promise from writeFile call
|
|
112
|
-
*/
|
|
113
|
-
function writeDefaultAppConfig (parentDir, flags) {
|
|
114
|
-
// write app config to .aio file
|
|
115
|
-
const appConfig = {
|
|
116
|
-
app: {
|
|
117
|
-
actions: 'actions',
|
|
118
|
-
dist: 'dist',
|
|
119
|
-
web: 'web-src'
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
return writeAio(appConfig, parentDir, flags)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Pretty prints the json object as a string.
|
|
127
|
-
* Delimited by 2 spaces.
|
|
128
|
-
*
|
|
129
|
-
* @param {object} json the json to pretty print
|
|
130
|
-
* @returns {string} the transformed json as a string
|
|
131
|
-
*/
|
|
132
|
-
function prettyPrintJson (json) {
|
|
133
|
-
return JSON.stringify(json, null, 2)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Confirmation prompt for overwriting, or merging a file if it already exists.
|
|
138
|
-
*
|
|
139
|
-
* @param {string} filePath the file to ovewrite
|
|
140
|
-
* @returns {object} ovewrite, merge, abort (properties, that are set to true if chosen)
|
|
141
|
-
*/
|
|
142
|
-
async function checkFileConflict (filePath) {
|
|
143
|
-
if (fs.existsSync(filePath)) {
|
|
144
|
-
const answer = await prompt([
|
|
145
|
-
{
|
|
146
|
-
type: 'expand',
|
|
147
|
-
message: `The file ${filePath} already exists:`,
|
|
148
|
-
name: 'conflict',
|
|
149
|
-
choices: [
|
|
150
|
-
{
|
|
151
|
-
key: 'o',
|
|
152
|
-
name: 'Overwrite',
|
|
153
|
-
value: 'overwrite'
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
key: 'm',
|
|
157
|
-
name: 'Merge',
|
|
158
|
-
value: 'merge'
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
key: 'x',
|
|
162
|
-
name: 'Abort',
|
|
163
|
-
value: 'abort'
|
|
164
|
-
}
|
|
165
|
-
]
|
|
166
|
-
}
|
|
167
|
-
])
|
|
168
|
-
|
|
169
|
-
switch (answer.conflict) {
|
|
170
|
-
case 'overwrite':
|
|
171
|
-
return { overwrite: true }
|
|
172
|
-
case 'merge':
|
|
173
|
-
return { merge: true }
|
|
174
|
-
case 'abort':
|
|
175
|
-
return { abort: true }
|
|
176
|
-
default:
|
|
177
|
-
return {}
|
|
178
|
-
}
|
|
179
|
-
} else {
|
|
180
|
-
return {}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Transform a json object to a flattened version. Any nesting is separated by the `separator` string.
|
|
186
|
-
* For example, if you have the `_` separator string, flattening this:
|
|
187
|
-
*
|
|
188
|
-
* {
|
|
189
|
-
* foo: {
|
|
190
|
-
* bar: 'a',
|
|
191
|
-
* baz: {
|
|
192
|
-
* faz: 'b'
|
|
193
|
-
* }
|
|
194
|
-
* }
|
|
195
|
-
* }
|
|
196
|
-
*
|
|
197
|
-
* const result = flattenObjectWithSeparator(json, {}, '', '_)
|
|
198
|
-
* The result would then be:
|
|
199
|
-
* {
|
|
200
|
-
* 'foo_bar': 'a',
|
|
201
|
-
* 'foo_baz_faz': 'b'
|
|
202
|
-
* }
|
|
203
|
-
*
|
|
204
|
-
* Any underscores in the object key are escaped with an underscore.
|
|
205
|
-
*
|
|
206
|
-
* @param {object} json the json object to transform
|
|
207
|
-
* @param {object} result the result object to initialize the function with
|
|
208
|
-
* @param {string} prefix the prefix to add to the final key
|
|
209
|
-
* @param {string} separator the separator string to separate the nested levels with
|
|
210
|
-
* @returns {object} the transformed json
|
|
211
|
-
*/
|
|
212
|
-
function flattenObjectWithSeparator (json, result = {}, prefix = AIO_ENV_PREFIX, separator = AIO_ENV_SEPARATOR) {
|
|
213
|
-
Object
|
|
214
|
-
.keys(json)
|
|
215
|
-
.forEach(key => {
|
|
216
|
-
const _key = key.replace(/_/gi, '__') // replace any underscores in key with double underscores
|
|
217
|
-
|
|
218
|
-
if (Array.isArray(json[key])) {
|
|
219
|
-
result[`${prefix}${_key}`] = JSON.stringify(json[key])
|
|
220
|
-
return result
|
|
221
|
-
} else if (typeof (json[key]) === 'object') {
|
|
222
|
-
flattenObjectWithSeparator(json[key], result, `${prefix}${_key}${separator}`)
|
|
223
|
-
} else {
|
|
224
|
-
result[`${prefix}${_key}`] = json[key]
|
|
225
|
-
return result
|
|
226
|
-
}
|
|
227
|
-
})
|
|
228
|
-
|
|
229
|
-
return result
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Split line from .env
|
|
234
|
-
*
|
|
235
|
-
* @param {string} line env line to split
|
|
236
|
-
* @returns {Array} tuple, first item is key, second item is value or null if it's a comment
|
|
237
|
-
*/
|
|
238
|
-
function splitEnvLine (line) {
|
|
239
|
-
const trimmedLine = line.trim()
|
|
240
|
-
if (trimmedLine.startsWith('#')) { // skip comments
|
|
241
|
-
aioLogger.debug(`splitEnvLine - processing comment: ${line}`)
|
|
242
|
-
return [trimmedLine, undefined]
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const items = line.split('=')
|
|
246
|
-
if (items.length >= 2) {
|
|
247
|
-
const key = items.shift().trim() // pop first element
|
|
248
|
-
const value = items.join('=').trimStart() // join the rest
|
|
249
|
-
|
|
250
|
-
return [key, value]
|
|
251
|
-
} else {
|
|
252
|
-
aioLogger.debug(`splitEnvLine - cannot process line: ${line}`)
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
return null
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Merge .env data
|
|
260
|
-
* (we don't want to go through the .env to json conversion)
|
|
261
|
-
* Note that comments will not be preserved.
|
|
262
|
-
*
|
|
263
|
-
* @param {string} oldEnv existing env values
|
|
264
|
-
* @param {string} newEnv new env values (takes precedence)
|
|
265
|
-
* @returns {string} the merged env data
|
|
266
|
-
*/
|
|
267
|
-
function mergeEnv (oldEnv, newEnv) {
|
|
268
|
-
aioLogger.debug(`mergeEnv - oldEnv: ${oldEnv}`)
|
|
269
|
-
aioLogger.debug(`mergeEnv - newEnv:${newEnv}`)
|
|
270
|
-
|
|
271
|
-
const result = {}
|
|
272
|
-
const NEWLINES = /\n|\r|\r\n/
|
|
273
|
-
|
|
274
|
-
aioLogger.debug(`mergeEnv - oldEnv:${oldEnv}`)
|
|
275
|
-
aioLogger.debug(`mergeEnv - newEnv:${newEnv}`)
|
|
276
|
-
|
|
277
|
-
const splitHelper = line => {
|
|
278
|
-
const tuple = splitEnvLine(line)
|
|
279
|
-
if (tuple) {
|
|
280
|
-
result[tuple[0]] = tuple[1]
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
oldEnv.split(NEWLINES).forEach(splitHelper)
|
|
285
|
-
newEnv.split(NEWLINES).forEach(splitHelper)
|
|
286
|
-
|
|
287
|
-
const mergedEnv = Object
|
|
288
|
-
.keys(result)
|
|
289
|
-
.map(key => result[key] !== undefined ? `${key}=${result[key]}` : key)
|
|
290
|
-
.join(EOL)
|
|
291
|
-
.concat(EOL) // add a new line
|
|
292
|
-
aioLogger.debug(`mergeEnv - mergedEnv:${mergedEnv}`)
|
|
293
|
-
|
|
294
|
-
return mergedEnv
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* Merge json data
|
|
299
|
-
*
|
|
300
|
-
* @param {string} oldData existing values
|
|
301
|
-
* @param {string} newData new values (takes precedence)
|
|
302
|
-
* @returns {object} the merged json
|
|
303
|
-
*/
|
|
304
|
-
function mergeJson (oldData, newData) {
|
|
305
|
-
const { values: oldJson } = loadConfigFile(Buffer.from(oldData))
|
|
306
|
-
const { values: newJson } = loadConfigFile(Buffer.from(newData))
|
|
307
|
-
|
|
308
|
-
aioLogger.debug(`mergeJson - oldJson:${prettyPrintJson(oldJson)}`)
|
|
309
|
-
aioLogger.debug(`mergeJson - newJson:${prettyPrintJson(newJson)}`)
|
|
310
|
-
|
|
311
|
-
const mergedJson = prettyPrintJson({ ...oldJson, ...newJson })
|
|
312
|
-
aioLogger.debug(`mergeJson - mergedJson:${mergedJson}`)
|
|
313
|
-
|
|
314
|
-
return mergedJson
|
|
315
|
-
}
|
|
1
|
+
const { loadAndValidateConfigFile, importConfigJson } = require('./import-helper')
|
|
2
|
+
const { SERVICE_API_KEY_ENV } = require('./defaults')
|
|
316
3
|
|
|
317
4
|
/**
|
|
318
|
-
*
|
|
5
|
+
* Imports the project's console config to the local environment.
|
|
319
6
|
*
|
|
320
|
-
* @param {string}
|
|
321
|
-
* @param {
|
|
322
|
-
* @
|
|
323
|
-
* @returns {string | object} the merged env or json data
|
|
7
|
+
* @param {string | Buffer} consoleConfigFileOrBuffer Name of config file to import or a buffer to write into
|
|
8
|
+
* @param {object} flags Flags for file writing
|
|
9
|
+
* @returns {Promise} Console config
|
|
324
10
|
*/
|
|
325
|
-
function
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
if (fileFormat === FILE_FORMAT_ENV) {
|
|
330
|
-
return mergeEnv(oldData, newData)
|
|
331
|
-
} else { // FILE_FORMAT_JSON default
|
|
332
|
-
return mergeJson(oldData, newData)
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Writes the data to file.
|
|
338
|
-
* Checks for conflicts and gives options to overwrite, merge, or abort.
|
|
339
|
-
*
|
|
340
|
-
* @param {string} destination the file to write to
|
|
341
|
-
* @param {string} data the data to write to disk
|
|
342
|
-
* @param {object} [flags] flags for file writing
|
|
343
|
-
* @param {boolean} [flags.overwrite=false] set to true to overwrite the existing .env file
|
|
344
|
-
* @param {boolean} [flags.merge=false] set to true to merge in the existing .env file (takes precedence over overwrite)
|
|
345
|
-
* @param {boolean} [flags.interactive=false] set to true to prompt the user for file overwrite
|
|
346
|
-
* @param {boolean} [flags.fileFormat=json] set the file format to write (defaults to json)
|
|
347
|
-
* @returns {Promise} the writefile
|
|
348
|
-
*/
|
|
349
|
-
async function writeFile (destination, data, flags = {}) {
|
|
350
|
-
const { overwrite = false, merge = false, fileFormat = FILE_FORMAT_JSON, interactive = false } = flags
|
|
351
|
-
aioLogger.debug(`writeFile - destination: ${destination} flags:${flags}`)
|
|
352
|
-
aioLogger.debug(`writeFile - data: ${data}`)
|
|
353
|
-
|
|
354
|
-
let answer = { overwrite, merge } // for non-interactive, get from the flags
|
|
355
|
-
|
|
356
|
-
if (interactive) {
|
|
357
|
-
answer = await checkFileConflict(destination)
|
|
358
|
-
aioLogger.debug(`writeFile - answer (interactive): ${JSON.stringify(answer)}`)
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
if (answer.abort) {
|
|
362
|
-
return
|
|
363
|
-
}
|
|
11
|
+
async function importConsoleConfig (consoleConfigFileOrBuffer, flags) {
|
|
12
|
+
const overwrite = flags.overwrite
|
|
13
|
+
const merge = flags.merge
|
|
14
|
+
let interactive = true
|
|
364
15
|
|
|
365
|
-
if (
|
|
366
|
-
|
|
367
|
-
const oldData = fs.readFileSync(destination, 'utf-8')
|
|
368
|
-
data = mergeData(oldData, data, fileFormat)
|
|
369
|
-
}
|
|
16
|
+
if (overwrite || merge) {
|
|
17
|
+
interactive = false
|
|
370
18
|
}
|
|
371
19
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
* Writes the json object as AIO_ env vars to the .env file in the specified parent folder.
|
|
379
|
-
*
|
|
380
|
-
* @param {object} json the json object to transform and write to disk
|
|
381
|
-
* @param {string} parentFolder the parent folder to write the .env file to
|
|
382
|
-
* @param {object} [flags] flags for file writing
|
|
383
|
-
* @param {boolean} [flags.overwrite=false] set to true to overwrite the existing .env file
|
|
384
|
-
* @param {boolean} [flags.merge=false] set to true to merge in the existing .env file (takes precedence over overwrite)
|
|
385
|
-
* @param {boolean} [flags.interactive=false] set to true to prompt the user for file overwrite
|
|
386
|
-
* @param {object} [extraEnvVars={}] extra environment variables key/value pairs to add to the generated .env.
|
|
387
|
-
* Extra variables are treated as raw and won't be rewritten to comply with aio-lib-core-config
|
|
388
|
-
* @returns {Promise} promise from writeFile call
|
|
389
|
-
*/
|
|
390
|
-
async function writeEnv (json, parentFolder, flags, extraEnvVars) {
|
|
391
|
-
aioLogger.debug(`writeEnv - json: ${JSON.stringify(json)} parentFolder:${parentFolder} flags:${flags} extraEnvVars:${extraEnvVars}`)
|
|
20
|
+
// before importing the config, first extract the service api key id
|
|
21
|
+
const { values: config } = loadAndValidateConfigFile(consoleConfigFileOrBuffer)
|
|
22
|
+
const project = config.project
|
|
23
|
+
const jwtConfig = project.workspace.details.credentials && project.workspace.details.credentials.find(c => c.jwt)
|
|
24
|
+
const serviceClientId = (jwtConfig && jwtConfig.jwt.client_id) || ''
|
|
25
|
+
const extraEnvVars = { [SERVICE_API_KEY_ENV]: serviceClientId }
|
|
392
26
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
const resultObject = { ...flattenObjectWithSeparator(json), ...extraEnvVars }
|
|
397
|
-
aioLogger.debug(`convertJsonToEnv - flattened and separated json: ${prettyPrintJson(resultObject)}`)
|
|
398
|
-
|
|
399
|
-
const data = Object
|
|
400
|
-
.keys(resultObject)
|
|
401
|
-
.map(key => `${key}=${resultObject[key]}`)
|
|
402
|
-
.join(EOL)
|
|
403
|
-
.concat(EOL)
|
|
404
|
-
aioLogger.debug(`writeEnv - data:${data}`)
|
|
405
|
-
|
|
406
|
-
return writeFile(destination, data, { ...flags, fileFormat: FILE_FORMAT_ENV })
|
|
27
|
+
await importConfigJson(consoleConfigFileOrBuffer, process.cwd(), { interactive, overwrite, merge }, extraEnvVars)
|
|
28
|
+
return config
|
|
407
29
|
}
|
|
408
30
|
|
|
409
31
|
/**
|
|
410
|
-
*
|
|
32
|
+
* Downloads the project's console config, returns it in a buffer
|
|
411
33
|
*
|
|
412
|
-
* @param {object}
|
|
34
|
+
* @param {object} consoleCLI Instance of the Console CLI sdk
|
|
35
|
+
* @param {object} config Global config
|
|
36
|
+
* @param {Array} supportedServices List of org supported services
|
|
37
|
+
* @returns {Promise<Buffer>} Project console config
|
|
413
38
|
*/
|
|
414
|
-
async function
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
id: org.id,
|
|
423
|
-
name: org.name,
|
|
424
|
-
code: org.ims_org_id
|
|
425
|
-
},
|
|
426
|
-
project: {
|
|
427
|
-
name: project.name,
|
|
428
|
-
id: project.id,
|
|
429
|
-
title: project.title,
|
|
430
|
-
description: project.description,
|
|
431
|
-
org_id: org.id
|
|
432
|
-
},
|
|
433
|
-
workspace: {
|
|
434
|
-
id: workspace.id,
|
|
435
|
-
name: workspace.name
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
config.set(CONSOLE_CONFIG_KEY, data)
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
/**
|
|
443
|
-
* Writes the json object to the .aio file in the specified parent folder.
|
|
444
|
-
*
|
|
445
|
-
* @param {object} json the json object to write to disk
|
|
446
|
-
* @param {string} parentFolder the parent folder to write the .aio file to
|
|
447
|
-
* @param {object} [flags] flags for file writing
|
|
448
|
-
* @param {boolean} [flags.overwrite=false] set to true to overwrite the existing .env file
|
|
449
|
-
* @param {boolean} [flags.merge=false] set to true to merge in the existing .env file (takes precedence over overwrite)
|
|
450
|
-
* @param {boolean} [flags.interactive=false] set to true to prompt the user for file overwrite
|
|
451
|
-
* @returns {Promise} promise from writeFile call
|
|
452
|
-
*/
|
|
453
|
-
async function writeAio (json, parentFolder, flags) {
|
|
454
|
-
aioLogger.debug(`writeAio - parentFolder:${parentFolder} flags:${flags}`)
|
|
455
|
-
aioLogger.debug(`writeAio - json: ${prettyPrintJson(json)}`)
|
|
456
|
-
|
|
457
|
-
const destination = path.join(parentFolder, AIO_FILE)
|
|
458
|
-
aioLogger.debug(`writeAio - destination: ${destination}`)
|
|
459
|
-
|
|
460
|
-
const data = prettyPrintJson(json)
|
|
461
|
-
return writeFile(destination, data, flags)
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
/**
|
|
465
|
-
* Transform runtime object value to what this plugin expects (single runtime namespace).
|
|
466
|
-
*
|
|
467
|
-
* @example
|
|
468
|
-
* from:
|
|
469
|
-
* {
|
|
470
|
-
* "namespaces": [
|
|
471
|
-
* {
|
|
472
|
-
* "name": "abc",
|
|
473
|
-
* "auth": "123"
|
|
474
|
-
* }
|
|
475
|
-
* ]
|
|
476
|
-
* }
|
|
477
|
-
* to:
|
|
478
|
-
* {
|
|
479
|
-
* "namespace": "abc",
|
|
480
|
-
* "auth": "123"
|
|
481
|
-
* }
|
|
482
|
-
*
|
|
483
|
-
* @param {object} runtime the runtime value to transform
|
|
484
|
-
* @returns {object} the transformed runtime object
|
|
485
|
-
* @private
|
|
486
|
-
*/
|
|
487
|
-
function transformRuntime (runtime) {
|
|
488
|
-
const newRuntime = (runtime.namespaces.length > 0) ? runtime.namespaces[0] : {}
|
|
489
|
-
if (newRuntime.name) {
|
|
490
|
-
newRuntime.namespace = newRuntime.name
|
|
491
|
-
delete newRuntime.name
|
|
492
|
-
// apihost is not sent in console config
|
|
493
|
-
newRuntime.apihost = defaults.defaultOwApihost
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
return newRuntime
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
/**
|
|
500
|
-
* Transforms a credentials array to an object, to what this plugin expects.
|
|
501
|
-
* Enrich with ims_org_id if it is a jwt credential.
|
|
502
|
-
*
|
|
503
|
-
* @example
|
|
504
|
-
* from:
|
|
505
|
-
* [{
|
|
506
|
-
* "id": "17561142",
|
|
507
|
-
* "name": "Project Foo",
|
|
508
|
-
* "integration_type": "oauthweb",
|
|
509
|
-
* "oauth2": {
|
|
510
|
-
* "client_id": "XYXYXYXYXYXYXYXYX",
|
|
511
|
-
* "client_secret": "XYXYXYXYZZZZZZ",
|
|
512
|
-
* "redirect_uri": "https://test123"
|
|
513
|
-
* }
|
|
514
|
-
* }]
|
|
515
|
-
* to:
|
|
516
|
-
* {
|
|
517
|
-
* "Project Foo": {
|
|
518
|
-
* "client_id": "XYXYXYXYXYXYXYXYX",
|
|
519
|
-
* "client_secret": "XYXYXYXYZZZZZZ",
|
|
520
|
-
* "redirect_uri": "https://test123"
|
|
521
|
-
* }
|
|
522
|
-
* }
|
|
523
|
-
*
|
|
524
|
-
* @param {Array} credentials array from Downloadable File Format
|
|
525
|
-
* @param {string} imsOrgId the ims org id
|
|
526
|
-
* @returns {object} the Credentials object
|
|
527
|
-
* @private
|
|
528
|
-
*/
|
|
529
|
-
function transformCredentials (credentials, imsOrgId) {
|
|
530
|
-
// find jwt credential
|
|
531
|
-
const credential = credentials.find(credential => typeof credential.jwt === 'object')
|
|
532
|
-
|
|
533
|
-
// enrich jwt credentials with ims org id
|
|
534
|
-
if (credential && credential.jwt && !credential.jwt.ims_org_id) {
|
|
535
|
-
aioLogger.debug('adding ims_org_id to ims.jwt config')
|
|
536
|
-
credential.jwt.ims_org_id = imsOrgId
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
return credentials.reduce((acc, credential) => {
|
|
540
|
-
// the json schema enforces for jwt OR oauth2 OR apiKey in a credential
|
|
541
|
-
const value = credential.oauth2 || credential.jwt || credential.api_key
|
|
542
|
-
|
|
543
|
-
const name = credential.name.replace(/ /gi, '_') // replace any spaces with underscores
|
|
544
|
-
acc[name] = value
|
|
545
|
-
|
|
546
|
-
return acc
|
|
547
|
-
}, {})
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
/**
|
|
551
|
-
* Trim the credentials array to only keep a reference to each integration credential.
|
|
552
|
-
* Replace spaces in the name with _ and lowercase the name
|
|
553
|
-
*
|
|
554
|
-
* @example
|
|
555
|
-
* from:
|
|
556
|
-
* [{
|
|
557
|
-
* "id": "17561142",
|
|
558
|
-
* "name": "Project Foo",
|
|
559
|
-
* "integration_type": "oauthweb",
|
|
560
|
-
* "oauth2": {
|
|
561
|
-
* "client_id": "XYXYXYXYXYXYXYXYX",
|
|
562
|
-
* "client_secret": "XYXYXYXYZZZZZZ",
|
|
563
|
-
* "redirect_uri": "https://test123"
|
|
564
|
-
* }
|
|
565
|
-
* }]
|
|
566
|
-
* to:
|
|
567
|
-
* [{
|
|
568
|
-
* "id": "17561142",
|
|
569
|
-
* "name": "project_foo",
|
|
570
|
-
* "integration_type": "oauthweb"
|
|
571
|
-
* }]
|
|
572
|
-
*
|
|
573
|
-
* @param {Array} credentials array from Downloadable File Format
|
|
574
|
-
* @returns {object} an array holding only the references to the credentials
|
|
575
|
-
* @private
|
|
576
|
-
*/
|
|
577
|
-
function credentialsReferences (credentials) {
|
|
578
|
-
return credentials.map(c => ({ id: c.id, name: c.name.replace(/ /gi, '_'), integration_type: c.integration_type }))
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
/**
|
|
582
|
-
* Import a downloadable config and write to the appropriate .env (credentials) and .aio (non-credentials) files.
|
|
583
|
-
*
|
|
584
|
-
* @param {string} configFileOrBuffer the path to the config file to import or a buffer
|
|
585
|
-
* @param {string} [destinationFolder=the current working directory] the path to the folder to write the .env and .aio files to
|
|
586
|
-
* @param {object} [flags={}] flags for file writing
|
|
587
|
-
* @param {boolean} [flags.overwrite=false] set to true to overwrite the existing .env file
|
|
588
|
-
* @param {boolean} [flags.merge=false] set to true to merge in the existing .env file (takes precedence over overwrite)
|
|
589
|
-
* @param {object} [extraEnvVars={}] extra environment variables key/value pairs to add to the generated .env.
|
|
590
|
-
* Extra variables are treated as raw and won't be rewritten to comply with aio-lib-core-config
|
|
591
|
-
* @returns {Promise} promise from writeAio call
|
|
592
|
-
*/
|
|
593
|
-
async function importConfigJson (configFileOrBuffer, destinationFolder = process.cwd(), flags = {}, extraEnvVars = {}) {
|
|
594
|
-
aioLogger.debug(`importConfigJson - configFileOrBuffer: ${configFileOrBuffer} destinationFolder:${destinationFolder} flags:${flags} extraEnvVars:${extraEnvVars}`)
|
|
595
|
-
|
|
596
|
-
const { values: config, format } = loadAndValidateConfigFile(configFileOrBuffer)
|
|
597
|
-
|
|
598
|
-
aioLogger.debug(`importConfigJson - format: ${format} config:${prettyPrintJson(config)} `)
|
|
599
|
-
|
|
600
|
-
const { runtime, credentials } = config.project.workspace.details
|
|
601
|
-
|
|
602
|
-
await writeEnv({
|
|
603
|
-
runtime: transformRuntime(runtime),
|
|
604
|
-
ims: { contexts: transformCredentials(credentials, config.project.org.ims_org_id) }
|
|
605
|
-
}, destinationFolder, flags, extraEnvVars)
|
|
606
|
-
|
|
607
|
-
// remove the credentials
|
|
608
|
-
delete config.project.workspace.details.runtime
|
|
609
|
-
// keep only a reference to the credentials in the aio config (hiding secrets)
|
|
610
|
-
config.project.workspace.details.credentials = credentialsReferences(config.project.workspace.details.credentials)
|
|
611
|
-
|
|
612
|
-
// write to the console config (for the `aio console` commands)
|
|
613
|
-
await writeConsoleConfig(config)
|
|
614
|
-
|
|
615
|
-
return writeAio(config, destinationFolder, flags)
|
|
39
|
+
async function downloadConsoleConfigToBuffer (consoleCLI, config, supportedServices) {
|
|
40
|
+
const workspaceConfig = await consoleCLI.getWorkspaceConfig(
|
|
41
|
+
config.org.id,
|
|
42
|
+
config.project.id,
|
|
43
|
+
config.workspace.id,
|
|
44
|
+
supportedServices
|
|
45
|
+
)
|
|
46
|
+
return Buffer.from(JSON.stringify(workspaceConfig))
|
|
616
47
|
}
|
|
617
48
|
|
|
618
49
|
module.exports = {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
loadAndValidateConfigFile,
|
|
622
|
-
writeConsoleConfig,
|
|
623
|
-
writeAio,
|
|
624
|
-
writeDefaultAppConfig,
|
|
625
|
-
writeEnv,
|
|
626
|
-
flattenObjectWithSeparator,
|
|
627
|
-
importConfigJson,
|
|
628
|
-
mergeEnv,
|
|
629
|
-
splitEnvLine,
|
|
630
|
-
CONSOLE_CONFIG_KEY
|
|
50
|
+
importConsoleConfig,
|
|
51
|
+
downloadConsoleConfigToBuffer
|
|
631
52
|
}
|
|
@@ -11,7 +11,7 @@ governing permissions and limitations under the License.
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
const rtLib = require('@adobe/aio-lib-runtime')
|
|
14
|
-
const { writeAio, writeEnv } = require('./import')
|
|
14
|
+
const { writeAio, writeEnv } = require('./import-helper')
|
|
15
15
|
const crypto = require('crypto')
|
|
16
16
|
const fs = require('fs-extra')
|
|
17
17
|
const path = require('path')
|