@contentstack/cli-cm-import 1.1.0 → 1.2.0
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 +4 -3
- package/oclif.manifest.json +1 -1
- package/package.json +8 -7
- package/src/app.js +90 -106
- package/src/commands/cm/stacks/import.js +8 -1
- package/src/config/default.js +9 -4
- package/src/lib/import/assets.js +291 -296
- package/src/lib/import/content-types.js +168 -247
- package/src/lib/import/custom-roles.js +110 -93
- package/src/lib/import/entries.js +216 -174
- package/src/lib/import/environments.js +40 -50
- package/src/lib/import/extensions.js +35 -41
- package/src/lib/import/global-fields.js +56 -68
- package/src/lib/import/labels.js +62 -61
- package/src/lib/import/locales.js +61 -64
- package/src/lib/import/marketplace-apps.js +293 -290
- package/src/lib/import/webhooks.js +45 -51
- package/src/lib/import/workflows.js +72 -62
- package/src/lib/util/extensionsUidReplace.js +9 -9
- package/src/lib/util/fs.js +91 -12
- package/src/lib/util/index.js +39 -3
- package/src/lib/util/log.js +7 -5
- package/src/lib/util/login.js +2 -1
- package/src/lib/util/lookupReplaceAssets.js +22 -10
- package/src/lib/util/lookupReplaceEntries.js +60 -60
- package/src/lib/util/marketplace-app-helper.js +25 -6
|
@@ -3,267 +3,283 @@
|
|
|
3
3
|
* Copyright (c) 2019 Contentstack LLC
|
|
4
4
|
* MIT Licensed
|
|
5
5
|
*/
|
|
6
|
-
const fs = require('fs')
|
|
7
|
-
const _ = require('lodash')
|
|
8
|
-
const path = require('path')
|
|
9
|
-
const chalk = require('chalk')
|
|
10
|
-
const mkdirp = require('mkdirp')
|
|
11
|
-
const { cliux,
|
|
12
|
-
|
|
13
|
-
let config = require('../../config/default')
|
|
14
|
-
const { addlogs: log } = require('../util/log')
|
|
15
|
-
const {
|
|
16
|
-
const sdk = require('../util/contentstack-management-sdk')
|
|
17
|
-
const { getInstalledExtensions } = require('../util/marketplace-app-helper')
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
this.
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const _ = require('lodash');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const mkdirp = require('mkdirp');
|
|
11
|
+
const { cliux, HttpClient, NodeCrypto } = require('@contentstack/cli-utilities');
|
|
12
|
+
|
|
13
|
+
let config = require('../../config/default');
|
|
14
|
+
const { addlogs: log } = require('../util/log');
|
|
15
|
+
const { readFileSync, writeFile } = require('../util/fs');
|
|
16
|
+
const sdk = require('../util/contentstack-management-sdk');
|
|
17
|
+
const { getDeveloperHubUrl, getInstalledExtensions } = require('../util/marketplace-app-helper');
|
|
18
|
+
|
|
19
|
+
module.exports = class ImportMarketplaceApps {
|
|
20
|
+
client;
|
|
21
|
+
marketplaceApps = [];
|
|
22
|
+
marketplaceAppsUid = [];
|
|
23
|
+
developerHubBaseUrl = null;
|
|
24
|
+
marketplaceAppFolderPath = '';
|
|
25
|
+
marketplaceAppConfig = config.modules.marketplace_apps;
|
|
26
|
+
|
|
27
|
+
constructor(credentialConfig) {
|
|
28
|
+
this.config = _.merge(config, credentialConfig);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async start() {
|
|
32
|
+
this.client = sdk.Client(this.config);
|
|
33
|
+
this.developerHubBaseUrl = await getDeveloperHubUrl();
|
|
34
|
+
this.marketplaceAppFolderPath = path.resolve(this.config.data, this.marketplaceAppConfig.dirName);
|
|
33
35
|
this.marketplaceApps = _.uniqBy(
|
|
34
|
-
|
|
35
|
-
'app_uid'
|
|
36
|
-
)
|
|
37
|
-
this.marketplaceAppsUid = _.map(this.marketplaceApps, 'uid')
|
|
38
|
-
|
|
39
|
-
if (!config.auth_token && !_.isEmpty(this.marketplaceApps)) {
|
|
40
|
-
cliux.print(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
readFileSync(path.resolve(this.marketplaceAppFolderPath, this.marketplaceAppConfig.fileName)),
|
|
37
|
+
'app_uid',
|
|
38
|
+
);
|
|
39
|
+
this.marketplaceAppsUid = _.map(this.marketplaceApps, 'uid');
|
|
40
|
+
|
|
41
|
+
if (!this.config.auth_token && !_.isEmpty(this.marketplaceApps)) {
|
|
42
|
+
cliux.print(
|
|
43
|
+
'WARNING!!! To import Marketplace apps, you must be logged in. Please check csdx auth:login --help to log in',
|
|
44
|
+
{ color: 'yellow' },
|
|
45
|
+
);
|
|
46
|
+
return Promise.resolve();
|
|
47
|
+
} else if (_.isEmpty(this.marketplaceApps)) {
|
|
48
|
+
return Promise.resolve();
|
|
44
49
|
}
|
|
45
50
|
|
|
46
|
-
await this.getOrgUid()
|
|
47
|
-
return this.handleInstallationProcess()
|
|
51
|
+
await this.getOrgUid();
|
|
52
|
+
return this.handleInstallationProcess();
|
|
48
53
|
}
|
|
49
54
|
|
|
50
55
|
/**
|
|
51
56
|
* @method getOrgUid
|
|
52
57
|
* @returns {Void}
|
|
53
58
|
*/
|
|
54
|
-
|
|
59
|
+
getOrgUid = async () => {
|
|
60
|
+
const self = this;
|
|
55
61
|
// NOTE get org uid
|
|
56
|
-
if (config.auth_token) {
|
|
57
|
-
const stack = await client
|
|
58
|
-
.stack({ api_key: config.target_stack, authtoken: config.auth_token })
|
|
62
|
+
if (self.config.auth_token) {
|
|
63
|
+
const stack = await this.client
|
|
64
|
+
.stack({ api_key: self.config.target_stack, authtoken: self.config.auth_token })
|
|
59
65
|
.fetch()
|
|
60
66
|
.catch((error) => {
|
|
61
|
-
console.log(error)
|
|
62
|
-
|
|
67
|
+
console.log(error);
|
|
68
|
+
log(self.config, 'Starting marketplace app installation', 'success');
|
|
69
|
+
});
|
|
63
70
|
|
|
64
71
|
if (stack && stack.org_uid) {
|
|
65
|
-
config.org_uid = stack.org_uid
|
|
72
|
+
self.config.org_uid = stack.org_uid;
|
|
66
73
|
}
|
|
67
74
|
}
|
|
68
|
-
}
|
|
75
|
+
};
|
|
69
76
|
|
|
70
77
|
/**
|
|
71
78
|
* @method handleInstallationProcess
|
|
72
79
|
* @returns {Promise<void>}
|
|
73
80
|
*/
|
|
74
|
-
|
|
75
|
-
const self = this
|
|
81
|
+
handleInstallationProcess = async () => {
|
|
82
|
+
const self = this;
|
|
76
83
|
const headers = {
|
|
77
|
-
authtoken: config.auth_token,
|
|
78
|
-
organization_uid: config.org_uid
|
|
79
|
-
}
|
|
80
|
-
const httpClient = new HttpClient().headers(headers)
|
|
81
|
-
const nodeCrypto = new NodeCrypto()
|
|
84
|
+
authtoken: self.config.auth_token,
|
|
85
|
+
organization_uid: self.config.org_uid,
|
|
86
|
+
};
|
|
87
|
+
const httpClient = new HttpClient().headers(headers);
|
|
88
|
+
const nodeCrypto = new NodeCrypto();
|
|
82
89
|
|
|
83
90
|
// NOTE install all private apps which is not available for stack.
|
|
84
|
-
await this.handleAllPrivateAppsCreationProcess({ httpClient })
|
|
85
|
-
const installedExtensions = await getInstalledExtensions(config)
|
|
91
|
+
await this.handleAllPrivateAppsCreationProcess({ httpClient });
|
|
92
|
+
const installedExtensions = await getInstalledExtensions(self.config);
|
|
86
93
|
|
|
87
94
|
// NOTE after private app installation, refetch marketplace apps from file
|
|
88
|
-
const marketplaceAppsFromFile =
|
|
89
|
-
|
|
95
|
+
const marketplaceAppsFromFile = readFileSync(
|
|
96
|
+
path.resolve(this.marketplaceAppFolderPath, self.marketplaceAppConfig.fileName),
|
|
97
|
+
);
|
|
98
|
+
this.marketplaceApps = _.filter(marketplaceAppsFromFile, ({ uid }) => _.includes(this.marketplaceAppsUid, uid));
|
|
90
99
|
|
|
91
|
-
log(config, 'Starting marketplace app installation', 'success')
|
|
100
|
+
log(self.config, 'Starting marketplace app installation', 'success');
|
|
92
101
|
|
|
93
102
|
for (let app of self.marketplaceApps) {
|
|
94
|
-
await self.installApps({ app, installedExtensions, httpClient, nodeCrypto })
|
|
103
|
+
await self.installApps({ app, installedExtensions, httpClient, nodeCrypto });
|
|
95
104
|
}
|
|
96
105
|
|
|
97
106
|
// NOTE get all the extension again after all apps installed (To manage uid mapping in content type, entries)
|
|
98
|
-
const extensions = await getInstalledExtensions(config)
|
|
99
|
-
const mapperFolderPath = path.join(config.data, 'mapper', 'marketplace_apps')
|
|
107
|
+
const extensions = await getInstalledExtensions(self.config);
|
|
108
|
+
const mapperFolderPath = path.join(self.config.data, 'mapper', 'marketplace_apps');
|
|
100
109
|
|
|
101
110
|
if (!fs.existsSync(mapperFolderPath)) {
|
|
102
|
-
mkdirp.sync(mapperFolderPath)
|
|
111
|
+
mkdirp.sync(mapperFolderPath);
|
|
103
112
|
}
|
|
104
113
|
|
|
105
|
-
const appUidMapperPath = path.join(mapperFolderPath, 'marketplace-apps.json')
|
|
106
|
-
const installedExt = _.map(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
)
|
|
114
|
+
const appUidMapperPath = path.join(mapperFolderPath, 'marketplace-apps.json');
|
|
115
|
+
const installedExt = _.map(extensions, (row) =>
|
|
116
|
+
_.pick(row, ['uid', 'title', 'type', 'app_uid', 'app_installation_uid']),
|
|
117
|
+
);
|
|
110
118
|
|
|
111
|
-
writeFile(appUidMapperPath, installedExt)
|
|
119
|
+
writeFile(appUidMapperPath, installedExt);
|
|
112
120
|
|
|
113
|
-
return Promise.resolve()
|
|
114
|
-
}
|
|
121
|
+
return Promise.resolve();
|
|
122
|
+
};
|
|
115
123
|
|
|
116
124
|
/**
|
|
117
125
|
* @method handleAllPrivateAppsCreationProcess
|
|
118
|
-
* @param {Object} options
|
|
126
|
+
* @param {Object} options
|
|
119
127
|
* @returns {Promise<void>}
|
|
120
128
|
*/
|
|
121
|
-
|
|
122
|
-
const self = this
|
|
123
|
-
const { httpClient } = options
|
|
124
|
-
const listOfExportedPrivateApps = _.filter(self.marketplaceApps, { visibility: 'private' })
|
|
129
|
+
handleAllPrivateAppsCreationProcess = async (options) => {
|
|
130
|
+
const self = this;
|
|
131
|
+
const { httpClient } = options;
|
|
132
|
+
const listOfExportedPrivateApps = _.filter(self.marketplaceApps, { visibility: 'private' });
|
|
125
133
|
|
|
126
134
|
if (_.isEmpty(listOfExportedPrivateApps)) {
|
|
127
|
-
return Promise.resolve()
|
|
135
|
+
return Promise.resolve();
|
|
128
136
|
}
|
|
129
137
|
|
|
130
138
|
// NOTE get list of developer-hub installed apps (private)
|
|
131
|
-
const installedDeveloperHubApps =
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
139
|
+
const installedDeveloperHubApps =
|
|
140
|
+
(await httpClient
|
|
141
|
+
.get(`${this.developerHubBaseUrl}/apps`)
|
|
142
|
+
.then(({ data: { data } }) => data)
|
|
143
|
+
.catch((err) => {
|
|
144
|
+
console.log(err);
|
|
145
|
+
})) || [];
|
|
136
146
|
const listOfNotInstalledPrivateApps = _.filter(
|
|
137
147
|
listOfExportedPrivateApps,
|
|
138
|
-
(app) => !_.includes(_.map(installedDeveloperHubApps, 'uid'), app.app_uid)
|
|
139
|
-
)
|
|
148
|
+
(app) => !_.includes(_.map(installedDeveloperHubApps, 'uid'), app.app_uid),
|
|
149
|
+
);
|
|
140
150
|
|
|
141
|
-
if (!_.isEmpty(listOfNotInstalledPrivateApps)) {
|
|
151
|
+
if (!_.isEmpty(listOfNotInstalledPrivateApps) && !self.config.forceMarketplaceAppsImport) {
|
|
142
152
|
const confirmation = await cliux.confirm(
|
|
143
|
-
chalk.yellow(
|
|
144
|
-
|
|
153
|
+
chalk.yellow(
|
|
154
|
+
`WARNING!!! The listed apps are private apps that are not available in the destination stack: \n\n${_.map(
|
|
155
|
+
listOfNotInstalledPrivateApps,
|
|
156
|
+
({ manifest: { name } }, index) => `${String(index + 1)}) ${name}`,
|
|
157
|
+
).join('\n')}\n\nWould you like to re-create the private app and then proceed with the installation? (y/n)`,
|
|
158
|
+
),
|
|
159
|
+
);
|
|
145
160
|
|
|
146
161
|
if (!confirmation) {
|
|
147
162
|
const continueProcess = await cliux.confirm(
|
|
148
|
-
chalk.yellow(
|
|
149
|
-
|
|
163
|
+
chalk.yellow(
|
|
164
|
+
`WARNING!!! Canceling the app re-creation may break the content type and entry import. Would you like to proceed? (y/n)`,
|
|
165
|
+
),
|
|
166
|
+
);
|
|
150
167
|
|
|
151
168
|
if (continueProcess) {
|
|
152
|
-
return resolve()
|
|
169
|
+
return resolve();
|
|
153
170
|
} else {
|
|
154
|
-
process.exit()
|
|
171
|
+
process.exit();
|
|
155
172
|
}
|
|
156
173
|
}
|
|
157
174
|
}
|
|
158
175
|
|
|
159
|
-
log(config, 'Starting developer hub private apps re-creation', 'success')
|
|
176
|
+
log(self.config, 'Starting developer hub private apps re-creation', 'success');
|
|
160
177
|
|
|
161
178
|
for (let app of listOfNotInstalledPrivateApps) {
|
|
162
|
-
await self.createAllPrivateAppsInDeveloperHub({ app, httpClient })
|
|
179
|
+
await self.createAllPrivateAppsInDeveloperHub({ app, httpClient });
|
|
163
180
|
}
|
|
164
181
|
|
|
165
|
-
return Promise.resolve()
|
|
166
|
-
}
|
|
182
|
+
return Promise.resolve();
|
|
183
|
+
};
|
|
167
184
|
|
|
168
185
|
/**
|
|
169
186
|
* @method removeUidFromManifestUILocations
|
|
170
|
-
* @param {Array<Object>} locations
|
|
187
|
+
* @param {Array<Object>} locations
|
|
171
188
|
* @returns {Array<Object>}
|
|
172
189
|
*/
|
|
173
|
-
|
|
190
|
+
removeUidFromManifestUILocations = (locations) => {
|
|
174
191
|
return _.map(locations, (location) => {
|
|
175
192
|
if (location.meta) {
|
|
176
|
-
location.meta = _.map(
|
|
177
|
-
location.meta,
|
|
178
|
-
(meta) => _.omit(meta, ['uid'])
|
|
179
|
-
)
|
|
193
|
+
location.meta = _.map(location.meta, (meta) => _.omit(meta, ['uid']));
|
|
180
194
|
}
|
|
181
195
|
|
|
182
|
-
return location
|
|
183
|
-
})
|
|
184
|
-
}
|
|
196
|
+
return location;
|
|
197
|
+
});
|
|
198
|
+
};
|
|
185
199
|
|
|
186
200
|
/**
|
|
187
201
|
* @method createAllPrivateAppsInDeveloperHub
|
|
188
|
-
* @param {Object} options
|
|
202
|
+
* @param {Object} options
|
|
189
203
|
* @returns {Promise<void>}
|
|
190
204
|
*/
|
|
191
|
-
|
|
192
|
-
const self = this
|
|
193
|
-
const { app, httpClient } = options
|
|
205
|
+
createAllPrivateAppsInDeveloperHub = async (options, uidCleaned = false) => {
|
|
206
|
+
const self = this;
|
|
207
|
+
const { app, httpClient } = options;
|
|
194
208
|
|
|
195
209
|
return new Promise((resolve) => {
|
|
196
|
-
if (
|
|
197
|
-
|
|
198
|
-
app.manifest.ui_location &&
|
|
199
|
-
!_.isEmpty(app.manifest.ui_location.locations)
|
|
200
|
-
) {
|
|
201
|
-
app.manifest.ui_location.locations = this.removeUidFromManifestUILocations(app.manifest.ui_location.locations)
|
|
210
|
+
if (!uidCleaned && app.manifest.ui_location && !_.isEmpty(app.manifest.ui_location.locations)) {
|
|
211
|
+
app.manifest.ui_location.locations = this.removeUidFromManifestUILocations(app.manifest.ui_location.locations);
|
|
202
212
|
}
|
|
203
|
-
httpClient.post(
|
|
204
|
-
`${config.extensionHost}/apps-api/apps`,
|
|
205
|
-
app.manifest
|
|
206
|
-
).then(async ({ data: result }) => {
|
|
207
|
-
const { name } = app.manifest
|
|
208
|
-
const { data, error, message } = result || {}
|
|
209
|
-
|
|
210
|
-
if (error) {
|
|
211
|
-
log(config, message, 'error')
|
|
212
|
-
|
|
213
|
-
if (_.toLower(error) === 'conflict') {
|
|
214
|
-
const appName = await cliux.inquire({
|
|
215
|
-
type: 'input',
|
|
216
|
-
name: 'name',
|
|
217
|
-
default: `Copy of ${app.manifest.name}`,
|
|
218
|
-
validate: this.validateAppName,
|
|
219
|
-
message: `${message}. Enter a new name to create an app.?`,
|
|
220
|
-
})
|
|
221
|
-
app.manifest.name = appName
|
|
222
|
-
|
|
223
|
-
await self.createAllPrivateAppsInDeveloperHub({ app, httpClient }, true)
|
|
224
|
-
.then(resolve)
|
|
225
|
-
.catch(resolve)
|
|
226
|
-
} else {
|
|
227
|
-
const confirmation = await cliux.confirm(
|
|
228
|
-
chalk.yellow('WARNING!!! The above error may have an impact if the failed app is referenced in entries/content type. Would you like to proceed? (y/n)')
|
|
229
|
-
)
|
|
230
213
|
|
|
231
|
-
|
|
232
|
-
|
|
214
|
+
httpClient
|
|
215
|
+
.post(`${this.developerHubBaseUrl}/apps`, app.manifest)
|
|
216
|
+
.then(async ({ data: result }) => {
|
|
217
|
+
const { name } = app.manifest;
|
|
218
|
+
const { data, error, message } = result || {};
|
|
219
|
+
|
|
220
|
+
if (error) {
|
|
221
|
+
log(self.config, message, 'error');
|
|
222
|
+
|
|
223
|
+
if (_.toLower(error) === 'conflict') {
|
|
224
|
+
const appName = self.config.forceMarketplaceAppsImport
|
|
225
|
+
? self.getAppName(app.manifest.name)
|
|
226
|
+
: await cliux.inquire({
|
|
227
|
+
type: 'input',
|
|
228
|
+
name: 'name',
|
|
229
|
+
default: `${app.manifest.name}-1`,
|
|
230
|
+
validate: this.validateAppName,
|
|
231
|
+
message: `${message}. Enter a new name to create an app.?`,
|
|
232
|
+
});
|
|
233
|
+
app.manifest.name = appName;
|
|
234
|
+
|
|
235
|
+
await self.createAllPrivateAppsInDeveloperHub({ app, httpClient }, true).then(resolve).catch(resolve);
|
|
233
236
|
} else {
|
|
234
|
-
|
|
237
|
+
if (self.config.forceMarketplaceAppsImport) return resolve();
|
|
238
|
+
|
|
239
|
+
const confirmation = await cliux.confirm(
|
|
240
|
+
chalk.yellow(
|
|
241
|
+
'WARNING!!! The above error may have an impact if the failed app is referenced in entries/content type. Would you like to proceed? (y/n)',
|
|
242
|
+
),
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
if (confirmation) {
|
|
246
|
+
resolve();
|
|
247
|
+
} else {
|
|
248
|
+
process.exit();
|
|
249
|
+
}
|
|
235
250
|
}
|
|
251
|
+
} else if (data) {
|
|
252
|
+
// NOTE new app installation
|
|
253
|
+
log(self.config, `${name} app created successfully.!`, 'success');
|
|
254
|
+
this.updatePrivateAppUid(app, data, app.manifest.name);
|
|
236
255
|
}
|
|
237
|
-
} else if (data) { // NOTE new app installation
|
|
238
|
-
log(config, `${name} app created successfully.!`, 'success')
|
|
239
|
-
this.updatePrivateAppUid(app, data, app.manifest.name)
|
|
240
|
-
}
|
|
241
256
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
257
|
+
resolve();
|
|
258
|
+
})
|
|
259
|
+
.catch((error) => {
|
|
260
|
+
if (error && (error.message || error.error_message)) {
|
|
261
|
+
log(self.config, error.message || error.error_message, 'error');
|
|
262
|
+
} else {
|
|
263
|
+
log(self.config, 'Something went wrong.!', 'error');
|
|
264
|
+
}
|
|
249
265
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
})
|
|
253
|
-
}
|
|
266
|
+
resolve();
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
};
|
|
254
270
|
|
|
255
271
|
/**
|
|
256
272
|
* @method updatePrivateAppUid
|
|
257
|
-
* @param {Object} app
|
|
258
|
-
* @param {Object} data
|
|
273
|
+
* @param {Object} app
|
|
274
|
+
* @param {Object} data
|
|
259
275
|
*/
|
|
260
|
-
|
|
261
|
-
const self = this
|
|
262
|
-
const allMarketplaceApps =
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
276
|
+
updatePrivateAppUid = (app, data, appName) => {
|
|
277
|
+
const self = this;
|
|
278
|
+
const allMarketplaceApps = readFileSync(
|
|
279
|
+
path.resolve(self.marketplaceAppFolderPath, self.marketplaceAppConfig.fileName),
|
|
280
|
+
);
|
|
281
|
+
const index = _.findIndex(allMarketplaceApps, { uid: app.uid, visibility: 'private' });
|
|
282
|
+
|
|
267
283
|
if (index > -1) {
|
|
268
284
|
allMarketplaceApps[index] = {
|
|
269
285
|
...allMarketplaceApps[index],
|
|
@@ -272,169 +288,156 @@ function importMarketplaceApps() {
|
|
|
272
288
|
old_title: allMarketplaceApps[index].title,
|
|
273
289
|
previous_data: [
|
|
274
290
|
...(allMarketplaceApps[index].old_data || []),
|
|
275
|
-
{ [`v${(allMarketplaceApps[index].old_data || []).length}`]: allMarketplaceApps[index] }
|
|
276
|
-
]
|
|
277
|
-
}
|
|
291
|
+
{ [`v${(allMarketplaceApps[index].old_data || []).length}`]: allMarketplaceApps[index] },
|
|
292
|
+
],
|
|
293
|
+
};
|
|
278
294
|
|
|
279
295
|
// NOTE Update app name
|
|
280
|
-
allMarketplaceApps[index].manifest.name = appName
|
|
296
|
+
allMarketplaceApps[index].manifest.name = appName;
|
|
281
297
|
|
|
282
|
-
writeFile(
|
|
283
|
-
path.join(self.marketplaceAppFolderPath, marketplaceAppConfig.fileName),
|
|
284
|
-
allMarketplaceApps
|
|
285
|
-
)
|
|
298
|
+
writeFile(path.join(self.marketplaceAppFolderPath, self.marketplaceAppConfig.fileName), allMarketplaceApps);
|
|
286
299
|
}
|
|
287
|
-
}
|
|
300
|
+
};
|
|
288
301
|
|
|
289
302
|
/**
|
|
290
303
|
* @method installApps
|
|
291
|
-
* @param {Object} options
|
|
304
|
+
* @param {Object} options
|
|
292
305
|
* @returns {Void}
|
|
293
306
|
*/
|
|
294
|
-
|
|
295
|
-
const self = this
|
|
296
|
-
const { app, installedExtensions, httpClient, nodeCrypto } = options
|
|
307
|
+
installApps = (options) => {
|
|
308
|
+
const self = this;
|
|
309
|
+
const { app, installedExtensions, httpClient, nodeCrypto } = options;
|
|
297
310
|
|
|
298
311
|
return new Promise((resolve, reject) => {
|
|
299
|
-
httpClient
|
|
300
|
-
`${self.
|
|
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
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
312
|
+
httpClient
|
|
313
|
+
.post(`${self.developerHubBaseUrl}/apps/${app.app_uid}/install`, {
|
|
314
|
+
target_type: 'stack',
|
|
315
|
+
target_uid: self.config.target_stack,
|
|
316
|
+
})
|
|
317
|
+
.then(async ({ data: result }) => {
|
|
318
|
+
let updateParam;
|
|
319
|
+
const { title } = app;
|
|
320
|
+
const { data, error, message, error_code, error_message } = result;
|
|
321
|
+
|
|
322
|
+
if (error || error_code) {
|
|
323
|
+
// NOTE if already installed copy only config data
|
|
324
|
+
log(self.config, `${message || error_message} - ${title}`, 'success');
|
|
325
|
+
const ext = _.find(installedExtensions, { app_uid: app.app_uid });
|
|
326
|
+
|
|
327
|
+
if (ext) {
|
|
328
|
+
if (!_.isEmpty(app.configuration) || !_.isEmpty(app.server_configuration)) {
|
|
329
|
+
cliux.print(
|
|
330
|
+
`WARNING!!! The ${title} app already exists and it may have its own configuration. But the current app you install has its own configuration which is used internally to manage content.`,
|
|
331
|
+
{ color: 'yellow' },
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
const configOption = self.config.forceMarketplaceAppsImport
|
|
335
|
+
? 'Update it with the new configuration.'
|
|
336
|
+
: await cliux.inquire({
|
|
337
|
+
choices: [
|
|
338
|
+
'Update it with the new configuration.',
|
|
339
|
+
'Do not update the configuration (WARNING!!! If you do not update the configuration, there may be some issues with the content which you import).',
|
|
340
|
+
'Exit',
|
|
341
|
+
],
|
|
342
|
+
type: 'list',
|
|
343
|
+
name: 'value',
|
|
344
|
+
message: 'Choose the option to proceed',
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
if (configOption === 'Exit') {
|
|
348
|
+
process.exit();
|
|
349
|
+
} else if (configOption === 'Update it with the new configuration.') {
|
|
350
|
+
updateParam = {
|
|
351
|
+
app,
|
|
352
|
+
nodeCrypto,
|
|
353
|
+
httpClient,
|
|
354
|
+
data: { ...ext, installation_uid: ext.app_installation_uid },
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
} else {
|
|
359
|
+
if (!self.config.forceMarketplaceAppsImport) {
|
|
360
|
+
cliux.print(`WARNING!!! ${message || error_message}`, { color: 'yellow' });
|
|
361
|
+
const confirmation = await cliux.confirm(
|
|
362
|
+
chalk.yellow(
|
|
363
|
+
'WARNING!!! The above error may have an impact if the failed app is referenced in entries/content type. Would you like to proceed? (y/n)',
|
|
364
|
+
),
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
if (!confirmation) {
|
|
368
|
+
process.exit();
|
|
337
369
|
}
|
|
338
370
|
}
|
|
339
371
|
}
|
|
340
|
-
} else {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
)
|
|
345
|
-
|
|
346
|
-
if (!confirmation) {
|
|
347
|
-
process.exit()
|
|
348
|
-
}
|
|
372
|
+
} else if (data) {
|
|
373
|
+
// NOTE new app installation
|
|
374
|
+
log(self.config, `${title} app installed successfully.!`, 'success');
|
|
375
|
+
updateParam = { data, app, nodeCrypto, httpClient };
|
|
349
376
|
}
|
|
350
|
-
} else if (data) { // NOTE new app installation
|
|
351
|
-
log(config, `${title} app installed successfully.!`, 'success')
|
|
352
|
-
updateParam = { data, app, nodeCrypto, httpClient }
|
|
353
|
-
}
|
|
354
377
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
}
|
|
378
|
+
if (updateParam) {
|
|
379
|
+
self.updateAppsConfig(updateParam).then(resolve).catch(reject);
|
|
380
|
+
} else {
|
|
381
|
+
resolve();
|
|
382
|
+
}
|
|
383
|
+
})
|
|
384
|
+
.catch((error) => {
|
|
385
|
+
if (error && (error.message || error.error_message)) {
|
|
386
|
+
log(self.config, error.message || error.error_message, 'error');
|
|
387
|
+
} else {
|
|
388
|
+
log(self.config, 'Something went wrong.!', 'error');
|
|
389
|
+
}
|
|
368
390
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
})
|
|
372
|
-
}
|
|
391
|
+
reject();
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
};
|
|
373
395
|
|
|
374
396
|
/**
|
|
375
397
|
* @method updateAppsConfig
|
|
376
398
|
* @param {Object<{ data, app, httpClient, nodeCrypto }>} param
|
|
377
399
|
* @returns {Promise<void>}
|
|
378
400
|
*/
|
|
379
|
-
|
|
401
|
+
updateAppsConfig = ({ data, app, httpClient, nodeCrypto }) => {
|
|
402
|
+
const self = this;
|
|
380
403
|
return new Promise((resolve, reject) => {
|
|
381
|
-
const payload = {}
|
|
382
|
-
const { title, configuration, server_configuration } = app
|
|
404
|
+
const payload = {};
|
|
405
|
+
const { title, configuration, server_configuration } = app;
|
|
383
406
|
|
|
384
407
|
if (!_.isEmpty(configuration)) {
|
|
385
|
-
payload['configuration'] = nodeCrypto.decrypt(configuration)
|
|
408
|
+
payload['configuration'] = nodeCrypto.decrypt(configuration);
|
|
386
409
|
}
|
|
387
410
|
if (!_.isEmpty(server_configuration)) {
|
|
388
|
-
payload['server_configuration'] = nodeCrypto.decrypt(server_configuration)
|
|
411
|
+
payload['server_configuration'] = nodeCrypto.decrypt(server_configuration);
|
|
389
412
|
}
|
|
390
413
|
|
|
391
414
|
if (_.isEmpty(data) || _.isEmpty(payload) || !data.installation_uid) {
|
|
392
|
-
resolve()
|
|
415
|
+
resolve();
|
|
393
416
|
} else {
|
|
394
|
-
httpClient
|
|
417
|
+
httpClient
|
|
418
|
+
.put(`${this.developerHubBaseUrl}/installations/${data.installation_uid}`, payload)
|
|
395
419
|
.then(() => {
|
|
396
|
-
log(config, `${title} app config updated successfully.!`, 'success')
|
|
397
|
-
})
|
|
398
|
-
.
|
|
420
|
+
log(self.config, `${title} app config updated successfully.!`, 'success');
|
|
421
|
+
})
|
|
422
|
+
.then(resolve)
|
|
423
|
+
.catch((error) => {
|
|
399
424
|
if (error && (error.message || error.error_message)) {
|
|
400
|
-
log(config,
|
|
425
|
+
log(self.config, error.message || error.error_message, 'error');
|
|
401
426
|
} else {
|
|
402
|
-
log(config, 'Something went wrong.!', 'error')
|
|
427
|
+
log(self.config, 'Something went wrong.!', 'error');
|
|
403
428
|
}
|
|
404
429
|
|
|
405
|
-
reject()
|
|
406
|
-
})
|
|
430
|
+
reject();
|
|
431
|
+
});
|
|
407
432
|
}
|
|
408
|
-
})
|
|
409
|
-
}
|
|
433
|
+
});
|
|
434
|
+
};
|
|
410
435
|
|
|
411
|
-
|
|
436
|
+
validateAppName = (name) => {
|
|
412
437
|
if (name.length < 3 || name.length > 20) {
|
|
413
438
|
return 'The app name should be within 3-20 characters long.';
|
|
414
439
|
}
|
|
415
440
|
|
|
416
441
|
return true;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
this.getDeveloperHubUrl = async () => {
|
|
420
|
-
const { cma, name } = configHandler.get('region') || {}
|
|
421
|
-
let developerHubBaseUrl = config.developerHubUrls[cma]
|
|
422
|
-
|
|
423
|
-
if (!developerHubBaseUrl) {
|
|
424
|
-
developerHubBaseUrl = await cliux.inquire({
|
|
425
|
-
type: 'input',
|
|
426
|
-
name: 'name',
|
|
427
|
-
validate: (url) => {
|
|
428
|
-
if (!url) return 'Developer-hub URL can\'t be empty.'
|
|
429
|
-
|
|
430
|
-
return true
|
|
431
|
-
},
|
|
432
|
-
message: `Enter the developer-hub base URL for the ${name} region - `,
|
|
433
|
-
})
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
return developerHubBaseUrl.startsWith('http') ? developerHubBaseUrl : `https://${developerHubBaseUrl}`
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
module.exports = new importMarketplaceApps()
|
|
442
|
+
};
|
|
443
|
+
};
|