@contentstack/cli-cm-import 1.2.2 → 1.2.3

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 CHANGED
@@ -37,7 +37,7 @@ $ npm install -g @contentstack/cli-cm-import
37
37
  $ csdx COMMAND
38
38
  running command...
39
39
  $ csdx (-v|--version|version)
40
- @contentstack/cli-cm-import/1.2.2 darwin-x64 node-v18.12.1
40
+ @contentstack/cli-cm-import/1.2.3 linux-x64 node-v16.18.1
41
41
  $ csdx --help [COMMAND]
42
42
  USAGE
43
43
  $ csdx COMMAND
@@ -68,7 +68,7 @@ OPTIONS
68
68
  -k, --stack-api-key=stack-api-key API key of the target stack
69
69
  -m, --module=module [optional] specific module name
70
70
  -y, --yes [optional] Override marketplace prompts
71
- --import-webhook-status=disable|current [default: disable] Webhook state
71
+ --import-webhook-status=disable|current [default: disable] [optional] Webhook state
72
72
 
73
73
  DESCRIPTION
74
74
  ...
@@ -1 +1 @@
1
- {"version":"1.2.2","commands":{"cm:stacks:import":{"id":"cm:stacks:import","description":"Import script for importing the content into the new stack\n...\nOnce you export content from the source stack, import it to your destination stack by using the cm:stacks:import command.\n","usage":"cm:stacks:import [-c <value>] [-k <value>] [-d <value>] [-a <value>] [--module <value>] [--backup-dir <value>] [--branch <value>] [--import-webhook-status disable|current]","pluginName":"@contentstack/cli-cm-import","pluginType":"core","aliases":["cm:import"],"examples":["csdx cm:stacks:import --stack-api-key <stack_api_key> --data-dir <path/of/export/destination/dir>","csdx cm:stacks:import --config <path/of/config/dir>","csdx cm:stacks:import --module <single module name>","csdx cm:stacks:import --module <single module name> --backup-dir <backup dir>","csdx cm:stacks:import --alias <management_token_alias>","csdx cm:stacks:import --alias <management_token_alias> --data-dir <path/of/export/destination/dir>","csdx cm:stacks:import --alias <management_token_alias> --config <path/of/config/file>","csdx cm:stacks:import --branch <branch name> --yes"],"flags":{"config":{"name":"config","type":"option","char":"c","description":"[optional] path of config file"},"stack-uid":{"name":"stack-uid","type":"option","char":"s","description":"API key of the target stack","hidden":true},"stack-api-key":{"name":"stack-api-key","type":"option","char":"k","description":"API key of the target stack"},"data":{"name":"data","type":"option","description":"path and location where data is stored","hidden":true},"data-dir":{"name":"data-dir","type":"option","char":"d","description":"path and location where data is stored"},"alias":{"name":"alias","type":"option","char":"a","description":"alias of the management token"},"management-token-alias":{"name":"management-token-alias","type":"option","description":"alias of the management token","hidden":true},"auth-token":{"name":"auth-token","type":"boolean","char":"A","description":"to use auth token","hidden":true,"allowNo":false},"module":{"name":"module","type":"option","char":"m","description":"[optional] specific module name"},"backup-dir":{"name":"backup-dir","type":"option","char":"b","description":"[optional] backup directory name when using specific module"},"branch":{"name":"branch","type":"option","char":"B","description":"[optional] branch name"},"import-webhook-status":{"name":"import-webhook-status","type":"option","description":"Webhook state","required":false,"options":["disable","current"],"default":"disable"},"yes":{"name":"yes","type":"boolean","char":"y","description":"[optional] Override marketplace prompts","required":false,"allowNo":false}},"args":[]}}}
1
+ {"version":"1.2.3","commands":{"cm:stacks:import":{"id":"cm:stacks:import","description":"Import script for importing the content into the new stack\n...\nOnce you export content from the source stack, import it to your destination stack by using the cm:stacks:import command.\n","usage":"cm:stacks:import [-c <value>] [-k <value>] [-d <value>] [-a <value>] [--module <value>] [--backup-dir <value>] [--branch <value>] [--import-webhook-status disable|current]","pluginName":"@contentstack/cli-cm-import","pluginType":"core","aliases":["cm:import"],"examples":["csdx cm:stacks:import --stack-api-key <stack_api_key> --data-dir <path/of/export/destination/dir>","csdx cm:stacks:import --config <path/of/config/dir>","csdx cm:stacks:import --module <single module name>","csdx cm:stacks:import --module <single module name> --backup-dir <backup dir>","csdx cm:stacks:import --alias <management_token_alias>","csdx cm:stacks:import --alias <management_token_alias> --data-dir <path/of/export/destination/dir>","csdx cm:stacks:import --alias <management_token_alias> --config <path/of/config/file>","csdx cm:stacks:import --branch <branch name> --yes"],"flags":{"config":{"name":"config","type":"option","char":"c","description":"[optional] path of config file"},"stack-uid":{"name":"stack-uid","type":"option","char":"s","description":"API key of the target stack","hidden":true},"stack-api-key":{"name":"stack-api-key","type":"option","char":"k","description":"API key of the target stack"},"data":{"name":"data","type":"option","description":"path and location where data is stored","hidden":true},"data-dir":{"name":"data-dir","type":"option","char":"d","description":"path and location where data is stored"},"alias":{"name":"alias","type":"option","char":"a","description":"alias of the management token"},"management-token-alias":{"name":"management-token-alias","type":"option","description":"alias of the management token","hidden":true},"auth-token":{"name":"auth-token","type":"boolean","char":"A","description":"to use auth token","hidden":true,"allowNo":false},"module":{"name":"module","type":"option","char":"m","description":"[optional] specific module name"},"backup-dir":{"name":"backup-dir","type":"option","char":"b","description":"[optional] backup directory name when using specific module"},"branch":{"name":"branch","type":"option","char":"B","description":"[optional] branch name"},"import-webhook-status":{"name":"import-webhook-status","type":"option","description":"[optional] Webhook state","required":false,"options":["disable","current"],"default":"disable"},"yes":{"name":"yes","type":"boolean","char":"y","description":"[optional] Override marketplace prompts","required":false,"allowNo":false}},"args":[]}}}
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@contentstack/cli-cm-import",
3
3
  "description": "Contentstack CLI plugin to import content into stack",
4
- "version": "1.2.2",
4
+ "version": "1.2.3",
5
5
  "author": "Contentstack",
6
6
  "bugs": "https://github.com/contentstack/cli/issues",
7
7
  "dependencies": {
8
- "@contentstack/cli-command": "^1.0.2",
9
- "@contentstack/management": "^1.3.0",
10
- "@contentstack/cli-utilities": "^1.0.3",
8
+ "@contentstack/cli-command": "^1.0.3",
9
+ "@contentstack/management": "^1.6.0",
10
+ "@contentstack/cli-utilities": "^1.0.4",
11
11
  "@oclif/command": "^1.8.16",
12
12
  "@oclif/config": "^1.18.3",
13
13
  "big-json": "^3.2.0",
package/src/app.js CHANGED
@@ -137,14 +137,24 @@ let allImport = async (config, types) => {
137
137
  );
138
138
  addlogs(config, 'The log for this is stored at ' + path.join(config.data, 'logs', 'import'), 'success');
139
139
  } else {
140
- addlogs(config, chalk.green('Stack: ' + config.target_stack + ' has been imported succesfully!'), 'success');
140
+ addlogs(
141
+ config,
142
+ chalk.green(
143
+ 'Data has been imported to stack ' + (config.destinationStackName || config.target_stack) + ' succesfully!',
144
+ ),
145
+ 'success',
146
+ );
141
147
  addlogs(config, 'The log for this is stored at ' + path.join(config.oldPath, 'logs', 'import'), 'success');
142
148
  }
143
149
  return true;
144
150
  } catch (error) {
145
151
  addlogs(
146
152
  config,
147
- chalk.red('Failed to migrate stack: ' + config.target_stack + '. Please check error logs for more info'),
153
+ chalk.red(
154
+ 'Failed to migrate stack: ' +
155
+ (config.destinationStackName || config.target_stack) +
156
+ '. Please check error logs for more info',
157
+ ),
148
158
  'error',
149
159
  );
150
160
  addlogs(config, formatError(error), 'error');
@@ -34,7 +34,7 @@ class ImportCommand extends Command {
34
34
  defaultConfig.data = data;
35
35
  }
36
36
 
37
- defaultConfig.forceMarketplaceAppsImport = importCommandFlags.yes
37
+ defaultConfig.forceStopMarketplaceAppsPrompt = importCommandFlags.yes;
38
38
 
39
39
  if (alias) {
40
40
  let managementTokens = self.getToken(alias);
@@ -173,7 +173,7 @@ ImportCommand.flags = {
173
173
  parse: printFlagDeprecation(['-B'], ['--branch']),
174
174
  }),
175
175
  'import-webhook-status': flags.string({
176
- description: 'Webhook state',
176
+ description: '[optional] Webhook state',
177
177
  options: ['disable', 'current'],
178
178
  required: false,
179
179
  default: 'disable',
@@ -181,8 +181,8 @@ ImportCommand.flags = {
181
181
  yes: flags.boolean({
182
182
  char: 'y',
183
183
  required: false,
184
- description: '[optional] Override marketplace prompts'
185
- })
184
+ description: '[optional] Override marketplace prompts',
185
+ }),
186
186
  };
187
187
 
188
188
  ImportCommand.aliases = ['cm:import'];
@@ -336,6 +336,9 @@ module.exports = {
336
336
  importConcurrency: 5,
337
337
  fetchConcurrency: 5,
338
338
  writeConcurrency: 5,
339
+ developerHubBaseUrl: '',
340
+ marketplaceAppEncryptionKey: 'nF2ejRQcTv',
341
+ getEncryptionKeyMaxRetry: 3,
339
342
  // useBackedupDir: '',
340
343
  // backupConcurrency: 10,
341
344
  };
@@ -103,13 +103,17 @@ module.exports = class ImportCustomRoles {
103
103
  } catch (error) {
104
104
  self.fails.push(customRole);
105
105
 
106
- if (error && error.errors && error.errors.name) {
107
- addlogs(self.config, chalk.red(`custom-role: ${customRole.name} already exists`), 'error');
106
+ if (((error && error.errors && error.errors.name) || '').includes('is not a unique.')) {
107
+ addlogs(self.config, chalk.red(`${customRole.name} role already exists`), 'info');
108
108
  } else {
109
- addlogs(self.config, chalk.red(`custom-role: ${customRole.name} failed`), 'error');
110
- }
109
+ if (!(error && error.errors && error.errors.name)) {
110
+ addlogs(self.config, chalk.red(`custom-role: ${customRole.name} already exists`), 'error');
111
+ } else {
112
+ addlogs(self.config, chalk.red(`custom-role: ${customRole.name} failed`), 'error');
113
+ }
111
114
 
112
- addlogs(self.config, formatError(error), 'error');
115
+ addlogs(self.config, formatError(error), 'error');
116
+ }
113
117
  }
114
118
  }
115
119
  addlogs(self.config, chalk.green('Custom-roles have been imported successfully!'), 'success');
@@ -780,19 +780,6 @@ EntriesImport.prototype = {
780
780
  }
781
781
  }
782
782
 
783
- if (flag.jsonRte) {
784
- self.ctJsonRte.push(uid);
785
- if (flag.jsonRteEmbeddedEntries) {
786
- self.ctJsonRteWithEntryRefs.push(uid);
787
- // pushing ct uid to refSchemas, because
788
- // repostEntries uses refSchemas content types for
789
- // reposting entries
790
- if (self.refSchemas.indexOf(uid) === -1) {
791
- self.refSchemas.push(uid);
792
- }
793
- }
794
- }
795
-
796
783
  // Replace extensions with new UID
797
784
  extension_suppress(contentTypeSchema.schema, config.preserveStackVersion, self.installedExtensions);
798
785
  }
@@ -1356,8 +1343,8 @@ EntriesImport.prototype = {
1356
1343
 
1357
1344
  if (entryRefs.length > 0) {
1358
1345
  entryRefs.forEach((entryRef) => {
1359
- if (!_.isEmpty(entry[entryRef.uid]) && entry[entryRef.uid].children) {
1360
- entry[entryRef.uid].children.splice(entryRef.index, 0, entryRef.value);
1346
+ if (!_.isEmpty(entry[element.uid]) && entry[element.uid].children) {
1347
+ entry[element.uid].children.splice(entryRef.index, 0, entryRef.value);
1361
1348
  }
1362
1349
  });
1363
1350
  }
@@ -30,7 +30,7 @@ module.exports = class ImportMarketplaceApps {
30
30
 
31
31
  async start() {
32
32
  this.client = sdk.Client(this.config);
33
- this.developerHubBaseUrl = await getDeveloperHubUrl();
33
+ this.developerHubBaseUrl = this.config.developerHubBaseUrl || (await getDeveloperHubUrl());
34
34
  this.marketplaceAppFolderPath = path.resolve(this.config.data, this.marketplaceAppConfig.dirName);
35
35
  this.marketplaceApps = _.uniqBy(
36
36
  readFileSync(path.resolve(this.marketplaceAppFolderPath, this.marketplaceAppConfig.fileName)),
@@ -74,18 +74,68 @@ module.exports = class ImportMarketplaceApps {
74
74
  }
75
75
  };
76
76
 
77
+ async getEncryptionKeyAndValidate(defaultValue, retry = 1) {
78
+ const appConfig =
79
+ _.find(this.marketplaceApps, 'configuration') ||
80
+ _.find(this.marketplaceApps, 'server_configuration.configuration');
81
+
82
+ if (appConfig) {
83
+ const encryptionKey = await cliux.inquire({
84
+ type: 'input',
85
+ name: 'name',
86
+ default: defaultValue,
87
+ validate: (key) => {
88
+ if (!key) return "Encryption key can't be empty.";
89
+
90
+ return true;
91
+ },
92
+ message: 'Enter marketplace app configurations encryption key',
93
+ });
94
+
95
+ try {
96
+ const nodeCrypto = new NodeCrypto({ encryptionKey });
97
+ nodeCrypto.decrypt(appConfig.configuration || appConfig.server_configuration);
98
+ } catch (error) {
99
+ if (retry < this.config.getEncryptionKeyMaxRetry && error.code === 'ERR_OSSL_EVP_BAD_DECRYPT') {
100
+ cliux.print('Provided encryption key is not valid or your data might be corrupted.!', { color: 'red' });
101
+ // NOTE max retry limit is 3
102
+ return this.getEncryptionKeyAndValidate(encryptionKey, retry + 1);
103
+ } else {
104
+ cliux.print('Maximum retry limit exceeded. Closing the process, please try again.!', { color: 'red' });
105
+ process.exit(1);
106
+ }
107
+ }
108
+
109
+ return encryptionKey;
110
+ }
111
+
112
+ return defaultValue;
113
+ }
114
+
77
115
  /**
78
116
  * @method handleInstallationProcess
79
117
  * @returns {Promise<void>}
80
118
  */
81
119
  handleInstallationProcess = async () => {
82
120
  const self = this;
121
+ const cryptoArgs = {};
83
122
  const headers = {
84
123
  authtoken: self.config.auth_token,
85
124
  organization_uid: self.config.org_uid,
86
125
  };
126
+
127
+ if (self.config.marketplaceAppEncryptionKey) {
128
+ cryptoArgs['encryptionKey'] = self.config.marketplaceAppEncryptionKey;
129
+ }
130
+
131
+ if (self.config.forceStopMarketplaceAppsPrompt) {
132
+ cryptoArgs['encryptionKey'] = self.config.marketplaceAppEncryptionKey;
133
+ } else {
134
+ cryptoArgs['encryptionKey'] = await self.getEncryptionKeyAndValidate(self.config.marketplaceAppEncryptionKey);
135
+ }
136
+
87
137
  const httpClient = new HttpClient().headers(headers);
88
- const nodeCrypto = new NodeCrypto();
138
+ const nodeCrypto = new NodeCrypto(cryptoArgs);
89
139
 
90
140
  // NOTE install all private apps which is not available for stack.
91
141
  await this.handleAllPrivateAppsCreationProcess({ httpClient });
@@ -148,7 +198,7 @@ module.exports = class ImportMarketplaceApps {
148
198
  (app) => !_.includes(_.map(installedDeveloperHubApps, 'uid'), app.app_uid),
149
199
  );
150
200
 
151
- if (!_.isEmpty(listOfNotInstalledPrivateApps) && !self.config.forceMarketplaceAppsImport) {
201
+ if (!_.isEmpty(listOfNotInstalledPrivateApps) && !self.config.forceStopMarketplaceAppsPrompt) {
152
202
  const confirmation = await cliux.confirm(
153
203
  chalk.yellow(
154
204
  `WARNING!!! The listed apps are private apps that are not available in the destination stack: \n\n${_.map(
@@ -258,12 +308,12 @@ module.exports = class ImportMarketplaceApps {
258
308
  log(self.config, message, 'error');
259
309
 
260
310
  if (_.toLower(error) === 'conflict') {
261
- const appName = self.config.forceMarketplaceAppsImport
311
+ const appName = self.config.forceStopMarketplaceAppsPrompt
262
312
  ? self.getAppName(app.manifest.name, appSuffix)
263
313
  : await cliux.inquire({
264
314
  type: 'input',
265
315
  name: 'name',
266
- default: `${app.manifest.name}-1`,
316
+ default: self.getAppName(app.manifest.name, appSuffix),
267
317
  validate: this.validateAppName,
268
318
  message: `${message}. Enter a new name to create an app.?`,
269
319
  });
@@ -274,7 +324,7 @@ module.exports = class ImportMarketplaceApps {
274
324
  .then(resolve)
275
325
  .catch(resolve);
276
326
  } else {
277
- if (self.config.forceMarketplaceAppsImport) return resolve();
327
+ if (self.config.forceStopMarketplaceAppsPrompt) return resolve();
278
328
 
279
329
  const confirmation = await cliux.confirm(
280
330
  chalk.yellow(
@@ -369,7 +419,7 @@ module.exports = class ImportMarketplaceApps {
369
419
  { color: 'yellow' },
370
420
  );
371
421
 
372
- const configOption = self.config.forceMarketplaceAppsImport
422
+ const configOption = self.config.forceStopMarketplaceAppsPrompt
373
423
  ? 'Update it with the new configuration.'
374
424
  : await cliux.inquire({
375
425
  choices: [
@@ -394,7 +444,7 @@ module.exports = class ImportMarketplaceApps {
394
444
  }
395
445
  }
396
446
  } else {
397
- if (!self.config.forceMarketplaceAppsImport) {
447
+ if (!self.config.forceStopMarketplaceAppsPrompt) {
398
448
  cliux.print(`WARNING!!! ${message || error_message}`, { color: 'yellow' });
399
449
  const confirmation = await cliux.confirm(
400
450
  chalk.yellow(
@@ -431,6 +481,27 @@ module.exports = class ImportMarketplaceApps {
431
481
  });
432
482
  };
433
483
 
484
+ updateConfigData(config) {
485
+ const configKeyMapper = {};
486
+ const serverConfigKeyMapper = {
487
+ cmsApiKey: this.config.target_stack,
488
+ };
489
+
490
+ if (!_.isEmpty(config.configuration) && !_.isEmpty(configKeyMapper)) {
491
+ _.forEach(_.keys(configKeyMapper), (key) => {
492
+ config.configuration[key] = configKeyMapper[key];
493
+ });
494
+ }
495
+
496
+ if (!_.isEmpty(config.server_configuration) && !_.isEmpty(serverConfigKeyMapper)) {
497
+ _.forEach(_.keys(serverConfigKeyMapper), (key) => {
498
+ config.server_configuration[key] = serverConfigKeyMapper[key];
499
+ });
500
+ }
501
+
502
+ return config;
503
+ }
504
+
434
505
  /**
435
506
  * @method updateAppsConfig
436
507
  * @param {Object<{ data, app, httpClient, nodeCrypto }>} param
@@ -439,7 +510,7 @@ module.exports = class ImportMarketplaceApps {
439
510
  updateAppsConfig = ({ data, app, httpClient, nodeCrypto }) => {
440
511
  const self = this;
441
512
  return new Promise((resolve, reject) => {
442
- const payload = {};
513
+ let payload = {};
443
514
  const { title, configuration, server_configuration } = app;
444
515
 
445
516
  if (!_.isEmpty(configuration)) {
@@ -449,6 +520,8 @@ module.exports = class ImportMarketplaceApps {
449
520
  payload['server_configuration'] = nodeCrypto.decrypt(server_configuration);
450
521
  }
451
522
 
523
+ payload = self.updateConfigData(payload);
524
+
452
525
  if (_.isEmpty(data) || _.isEmpty(payload) || !data.installation_uid) {
453
526
  resolve();
454
527
  } else {
@@ -3,13 +3,13 @@ const sdk = require('./contentstack-management-sdk');
3
3
  const { cliux, HttpClient, configHandler } = require('@contentstack/cli-utilities');
4
4
 
5
5
  const getInstalledExtensions = (config) => {
6
- const client = sdk.Client(config)
6
+ const client = sdk.Client(config);
7
7
 
8
8
  return new Promise((resolve, reject) => {
9
9
  const queryRequestOptions = {
10
- include_marketplace_extensions: true
11
- }
12
- const { target_stack: api_key, management_token, auth_token } = config || {}
10
+ include_marketplace_extensions: true,
11
+ };
12
+ const { target_stack: api_key, management_token, auth_token } = config || {};
13
13
 
14
14
  if (api_key && management_token) {
15
15
  return client
@@ -18,21 +18,22 @@ const getInstalledExtensions = (config) => {
18
18
  .query(queryRequestOptions)
19
19
  .find()
20
20
  .then(({ items }) => resolve(items))
21
- .catch(reject)
21
+ .catch(reject);
22
22
  } else if (api_key && auth_token) {
23
23
  const { cma } = configHandler.get('region') || {};
24
24
  const headers = {
25
25
  api_key,
26
- authtoken: auth_token
27
- }
26
+ authtoken: auth_token,
27
+ };
28
28
  const httpClient = new HttpClient().headers(headers);
29
- httpClient.get(`${cma}/v3/extensions/?include_marketplace_extensions=true`)
30
- .then(({ data: { extensions } }) => resolve(extensions))
29
+ httpClient
30
+ .get(`${cma}/v3/extensions/?include_marketplace_extensions=true`)
31
+ .then(({ data: { extensions } }) => resolve(extensions));
31
32
  } else {
32
- resolve([])
33
+ resolve([]);
33
34
  }
34
- })
35
- }
35
+ });
36
+ };
36
37
 
37
38
  const getDeveloperHubUrl = async () => {
38
39
  const { cma, name } = configHandler.get('region') || {};
@@ -47,11 +48,11 @@ const getDeveloperHubUrl = async () => {
47
48
 
48
49
  return true;
49
50
  },
50
- message: `Enter the developer-hub base URL for the ${name} region - `,
51
+ message: `Enter the developer-hub base URL for the ${name} region -`,
51
52
  });
52
53
  }
53
54
 
54
55
  return developerHubBaseUrl.startsWith('http') ? developerHubBaseUrl : `https://${developerHubBaseUrl}`;
55
- }
56
+ };
56
57
 
57
- module.exports = { getInstalledExtensions, getDeveloperHubUrl }
58
+ module.exports = { getInstalledExtensions, getDeveloperHubUrl };