@contentstack/cli-cm-import 1.13.2 → 1.14.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 CHANGED
@@ -47,7 +47,7 @@ $ npm install -g @contentstack/cli-cm-import
47
47
  $ csdx COMMAND
48
48
  running command...
49
49
  $ csdx (--version)
50
- @contentstack/cli-cm-import/1.13.2 linux-x64 node-v18.19.0
50
+ @contentstack/cli-cm-import/1.14.0 linux-x64 node-v18.19.1
51
51
  $ csdx --help [COMMAND]
52
52
  USAGE
53
53
  $ csdx COMMAND
@@ -22,12 +22,14 @@ class ImportCommand extends cli_command_1.Command {
22
22
  const moduleImporter = new import_1.ModuleImporter(managementAPIClient, importConfig);
23
23
  const result = await moduleImporter.start();
24
24
  if (!(result === null || result === void 0 ? void 0 : result.noSuccessMsg)) {
25
- (0, utils_1.log)(importConfig, `The content has been imported to the stack ${importConfig.apiKey} successfully!`, 'success');
25
+ (0, utils_1.log)(importConfig, importConfig.stackName
26
+ ? `Successfully imported the content to the stack named ${importConfig.stackName} with the API key ${importConfig.apiKey} .`
27
+ : `The content has been imported to the stack ${importConfig.apiKey} successfully!`, 'success');
26
28
  }
27
29
  (0, utils_1.log)(importConfig, `The log has been stored at '${node_path_1.default.join(importConfig.backupDir, 'logs', 'import')}'`, 'success');
28
30
  }
29
31
  catch (error) {
30
- (0, utils_1.log)({ data: backupDir }, `Failed to import stack content - ${(0, utils_1.formatError)(error)}`, 'error');
32
+ (0, utils_1.log)({ data: backupDir !== null && backupDir !== void 0 ? backupDir : node_path_1.default.join(backupDir || __dirname, 'logs', 'import') }, `Failed to import stack content - ${(0, utils_1.formatError)(error)}`, 'error');
31
33
  (0, utils_1.log)({ data: backupDir }, `The log has been stored at ${{ data: backupDir } ? node_path_1.default.join(backupDir || __dirname, 'logs', 'import') : node_path_1.default.join(__dirname, 'logs')}`, 'info');
32
34
  }
33
35
  }
@@ -148,11 +148,7 @@ const config = {
148
148
  taxonomies: {
149
149
  dirName: 'taxonomies',
150
150
  fileName: 'taxonomies.json',
151
- },
152
- terms: {
153
- dirName: 'terms',
154
- fileName: 'terms.json',
155
- },
151
+ }
156
152
  },
157
153
  languagesCode: [
158
154
  'af-za',
@@ -18,6 +18,10 @@ class ModuleImporter {
18
18
  this.importConfig = importConfig;
19
19
  }
20
20
  async start() {
21
+ if (!this.importConfig.management_token) {
22
+ const stackName = await this.stackAPIClient.fetch();
23
+ this.importConfig.stackName = stackName.name;
24
+ }
21
25
  if (this.importConfig.branchName) {
22
26
  await (0, utils_1.validateBranch)(this.stackAPIClient, this.importConfig, this.importConfig.branchName);
23
27
  }
@@ -3,7 +3,7 @@ import { ImportConfig, ModuleClassParams } from '../../types';
3
3
  export type AdditionalKeys = {
4
4
  backupDir: string;
5
5
  };
6
- export type ApiModuleType = 'create-assets' | 'replace-assets' | 'publish-assets' | 'create-assets-folder' | 'create-extensions' | 'update-extensions' | 'create-locale' | 'update-locale' | 'create-gfs' | 'create-cts' | 'update-cts' | 'update-gfs' | 'create-environments' | 'create-labels' | 'update-labels' | 'create-webhooks' | 'create-workflows' | 'create-custom-role' | 'create-entries' | 'update-entries' | 'publish-entries' | 'delete-entries' | 'create-taxonomies' | 'create-terms';
6
+ export type ApiModuleType = 'create-assets' | 'replace-assets' | 'publish-assets' | 'create-assets-folder' | 'create-extensions' | 'update-extensions' | 'create-locale' | 'update-locale' | 'create-gfs' | 'create-cts' | 'update-cts' | 'update-gfs' | 'create-environments' | 'create-labels' | 'update-labels' | 'create-webhooks' | 'create-workflows' | 'create-custom-role' | 'create-entries' | 'update-entries' | 'publish-entries' | 'delete-entries' | 'create-taxonomies' | 'create-terms' | 'import-taxonomy';
7
7
  export type ApiOptions = {
8
8
  uid?: string;
9
9
  url?: string;
@@ -122,6 +122,11 @@ class BaseClass {
122
122
  additionalInfo,
123
123
  apiData: includeParamOnCompletion ? apiData : undefined,
124
124
  });
125
+ if (!apiData ||
126
+ (entity === 'publish-entries' && !apiData.entryUid) ||
127
+ (entity === 'update-extensions' && !apiData.uid)) {
128
+ return Promise.resolve();
129
+ }
125
130
  switch (entity) {
126
131
  case 'create-assets-folder':
127
132
  return this.stack
@@ -154,6 +159,16 @@ class BaseClass {
154
159
  .create({ extension: (0, omit_1.default)(apiData, ['uid']) })
155
160
  .then(onSuccess)
156
161
  .catch(onReject);
162
+ case 'update-extensions':
163
+ return this.stack
164
+ .extension(apiData.uid)
165
+ .fetch()
166
+ .then((extension) => {
167
+ extension.scope = apiData.scope;
168
+ return extension.update();
169
+ })
170
+ .then(onSuccess)
171
+ .catch(onReject);
157
172
  case 'create-locale':
158
173
  return this.stack
159
174
  .locale()
@@ -169,14 +184,8 @@ class BaseClass {
169
184
  case 'create-cts':
170
185
  return this.stack.contentType().create(apiData).then(onSuccess).catch(onReject);
171
186
  case 'update-cts':
172
- if (!apiData) {
173
- return Promise.resolve();
174
- }
175
187
  return apiData.update().then(onSuccess).catch(onReject);
176
188
  case 'update-gfs':
177
- if (!apiData) {
178
- return Promise.resolve();
179
- }
180
189
  return apiData.update().then(onSuccess).catch(onReject);
181
190
  case 'create-environments':
182
191
  return this.stack
@@ -218,9 +227,6 @@ class BaseClass {
218
227
  .then(onSuccess)
219
228
  .catch(onReject);
220
229
  case 'create-entries':
221
- if (!apiData) {
222
- return Promise.resolve();
223
- }
224
230
  if ((_a = additionalInfo[apiData === null || apiData === void 0 ? void 0 : apiData.uid]) === null || _a === void 0 ? void 0 : _a.isLocalized) {
225
231
  return apiData.update({ locale: additionalInfo.locale }).then(onSuccess).catch(onReject);
226
232
  }
@@ -231,14 +237,8 @@ class BaseClass {
231
237
  .then(onSuccess)
232
238
  .catch(onReject);
233
239
  case 'update-entries':
234
- if (!apiData) {
235
- return Promise.resolve();
236
- }
237
240
  return apiData.update({ locale: additionalInfo.locale }).then(onSuccess).catch(onReject);
238
241
  case 'publish-entries':
239
- if (!apiData || !apiData.entryUid) {
240
- return Promise.resolve();
241
- }
242
242
  return this.stack
243
243
  .contentType(additionalInfo.cTUid)
244
244
  .entry(apiData.entryUid)
@@ -258,14 +258,17 @@ class BaseClass {
258
258
  case 'create-taxonomies':
259
259
  return this.stack.taxonomy().create({ taxonomy: apiData }).then(onSuccess).catch(onReject);
260
260
  case 'create-terms':
261
- if (apiData === null || apiData === void 0 ? void 0 : apiData.taxonomy_uid) {
262
- return this.stack
263
- .taxonomy(apiData.taxonomy_uid)
264
- .terms()
265
- .create({ term: apiData })
266
- .then(onSuccess)
267
- .catch(onReject);
261
+ return this.stack
262
+ .taxonomy(apiData.taxonomy_uid)
263
+ .terms()
264
+ .create({ term: apiData })
265
+ .then(onSuccess)
266
+ .catch(onReject);
267
+ case 'import-taxonomy':
268
+ if (!apiData || !apiData.filePath) {
269
+ return Promise.resolve();
268
270
  }
271
+ return this.stack.taxonomy(uid).import({ taxonomy: apiData.filePath }).then(onSuccess).catch(onReject);
269
272
  default:
270
273
  return Promise.resolve();
271
274
  }
@@ -32,6 +32,7 @@ export default class ContentTypesImport extends BaseClass {
32
32
  private gFsConfig;
33
33
  private taxonomiesPath;
34
34
  taxonomies: Record<string, unknown>;
35
+ private extPendingPath;
35
36
  constructor({ importConfig, stackAPIClient }: ModuleClassParams);
36
37
  start(): Promise<any>;
37
38
  seedCTs(): Promise<any>;
@@ -55,4 +56,5 @@ export default class ContentTypesImport extends BaseClass {
55
56
  * @returns {ApiOptions} ApiOptions
56
57
  */
57
58
  serializeUpdateGFs(apiOptions: ApiOptions): ApiOptions;
59
+ updatePendingExtensions(): Promise<any>;
58
60
  }
@@ -39,6 +39,7 @@ class ContentTypesImport extends base_class_1.default {
39
39
  this.createdGFs = [];
40
40
  this.pendingGFs = [];
41
41
  this.taxonomiesPath = path.join(importConfig.data, 'mapper/taxonomies', 'success.json');
42
+ this.extPendingPath = path.join(importConfig.data, 'mapper', 'extensions', 'pending_extensions.js');
42
43
  }
43
44
  async start() {
44
45
  /**
@@ -63,6 +64,9 @@ class ContentTypesImport extends base_class_1.default {
63
64
  if (this.fieldRules.length > 0) {
64
65
  await utils_1.fsUtil.writeFile(path.join(this.cTsFolderPath, 'field_rules_uid.json'), this.fieldRules);
65
66
  }
67
+ (0, utils_1.log)(this.importConfig, 'Updating the extensions...', 'success');
68
+ await this.updatePendingExtensions();
69
+ (0, utils_1.log)(this.importConfig, 'Successfully updated the extensions.', 'success');
66
70
  await this.updatePendingGFs().catch((error) => {
67
71
  (0, utils_1.log)(this.importConfig, `Error while updating pending global field ${(0, utils_1.formatError)(error)}`, 'error');
68
72
  });
@@ -190,5 +194,39 @@ class ContentTypesImport extends base_class_1.default {
190
194
  apiOptions.apiData = globalFieldPayload;
191
195
  return apiOptions;
192
196
  }
197
+ async updatePendingExtensions() {
198
+ let apiContent = utils_1.fsUtil.readFile(this.extPendingPath);
199
+ if (apiContent.length === 0) {
200
+ (0, utils_1.log)(this.importConfig, `No extensions found to be updated.`, 'success');
201
+ return;
202
+ }
203
+ const onSuccess = ({ response, apiData: { uid, title } = { uid: null, title: '' } }) => {
204
+ (0, utils_1.log)(this.importConfig, `Successfully updated the '${response.title}' extension.`, 'success');
205
+ };
206
+ const onReject = ({ error, apiData }) => {
207
+ var _a;
208
+ const { uid } = apiData;
209
+ if ((_a = error === null || error === void 0 ? void 0 : error.errors) === null || _a === void 0 ? void 0 : _a.title) {
210
+ if (!this.importConfig.skipExisting) {
211
+ (0, utils_1.log)(this.importConfig, `Extension '${uid}' already exists.`, 'info');
212
+ }
213
+ }
214
+ else {
215
+ (0, utils_1.log)(this.importConfig, `Failed to update '${uid}' extension due to ${(0, utils_1.formatError)(error)}.`, 'error');
216
+ (0, utils_1.log)(this.importConfig, error, 'error');
217
+ }
218
+ };
219
+ return await this.makeConcurrentCall({
220
+ apiContent,
221
+ processName: 'update extensions',
222
+ apiParams: {
223
+ reject: onReject.bind(this),
224
+ resolve: onSuccess.bind(this),
225
+ entity: 'update-extensions',
226
+ includeParamOnCompletion: true,
227
+ },
228
+ concurrencyLimit: this.importConfig.concurrency || this.importConfig.fetchConcurrency || 1,
229
+ }, undefined, false);
230
+ }
193
231
  }
194
232
  exports.default = ContentTypesImport;
@@ -12,6 +12,8 @@ export default class ImportExtensions extends BaseClass {
12
12
  private extSuccess;
13
13
  private extFailed;
14
14
  private existingExtensions;
15
+ private extPendingPath;
16
+ private extensionObject;
15
17
  constructor({ importConfig, stackAPIClient }: ModuleClassParams);
16
18
  /**
17
19
  * @method start
@@ -25,4 +27,6 @@ export default class ImportExtensions extends BaseClass {
25
27
  element: Record<string, string>;
26
28
  isLastRequest: boolean;
27
29
  }): Promise<unknown>;
30
+ getContentTypesInScope(): void;
31
+ updateUidExtension(): void;
28
32
  }
@@ -16,10 +16,12 @@ class ImportExtensions extends base_class_1.default {
16
16
  this.extUidMapperPath = (0, node_path_1.join)(this.mapperDirPath, 'uid-mapping.json');
17
17
  this.extSuccessPath = (0, node_path_1.join)(this.mapperDirPath, 'success.json');
18
18
  this.extFailsPath = (0, node_path_1.join)(this.mapperDirPath, 'fails.json');
19
+ this.extPendingPath = (0, node_path_1.join)(this.mapperDirPath, 'pending_extensions.js');
19
20
  this.extFailed = [];
20
21
  this.extSuccess = [];
21
22
  this.existingExtensions = [];
22
23
  this.extUidMapper = {};
24
+ this.extensionObject = [];
23
25
  }
24
26
  /**
25
27
  * @method start
@@ -40,7 +42,12 @@ class ImportExtensions extends base_class_1.default {
40
42
  this.extUidMapper = utils_1.fileHelper.fileExistsSync(this.extUidMapperPath)
41
43
  ? utils_1.fsUtil.readFile((0, node_path_1.join)(this.extUidMapperPath), true)
42
44
  : {};
45
+ // Check whether the scope of an extension contains content-types in scope
46
+ // Remove the scope and store the scope with uid in pending extensions
47
+ this.getContentTypesInScope();
43
48
  await this.importExtensions();
49
+ // Update the uid of the extension
50
+ this.updateUidExtension();
44
51
  // Note: if any extensions present, then update it
45
52
  if (this.importConfig.replaceExisting && this.existingExtensions.length > 0) {
46
53
  await this.replaceExtensions().catch((error) => {
@@ -167,5 +174,25 @@ class ImportExtensions extends base_class_1.default {
167
174
  }
168
175
  });
169
176
  }
177
+ getContentTypesInScope() {
178
+ const extension = (0, values_1.default)(this.extensions);
179
+ extension.forEach((ext) => {
180
+ var _a;
181
+ let ct = ((_a = ext === null || ext === void 0 ? void 0 : ext.scope) === null || _a === void 0 ? void 0 : _a.content_types) || [];
182
+ if ((ct.length === 1 && ct[0] !== '$all') || (ct === null || ct === void 0 ? void 0 : ct.length) > 1) {
183
+ (0, utils_1.log)(this.importConfig, `Removing the content-types ${ct.join(',')} from the extension ${ext.title} ...`, 'info');
184
+ const { uid, scope } = ext;
185
+ this.extensionObject.push({ uid, scope });
186
+ delete ext.scope;
187
+ this.extensions[ext.uid] = ext;
188
+ }
189
+ });
190
+ }
191
+ updateUidExtension() {
192
+ for (let i in this.extensionObject) {
193
+ this.extensionObject[i].uid = this.extUidMapper[this.extensionObject[i].uid];
194
+ }
195
+ utils_1.fsUtil.writeFile(this.extPendingPath, this.extensionObject);
196
+ }
170
197
  }
171
198
  exports.default = ImportExtensions;
@@ -7,17 +7,13 @@ export default class ImportTaxonomies extends BaseClass {
7
7
  private taxFailsPath;
8
8
  private taxonomiesConfig;
9
9
  private taxonomies;
10
- private termsFolderPath;
11
10
  private termsMapperDirPath;
12
- private termsConfig;
13
11
  private termsSuccessPath;
14
12
  private termsFailsPath;
15
- taxonomiesSuccess: Record<string, unknown>;
16
- taxonomiesFailed: Record<string, unknown>;
17
- termsSuccess: Record<string, Record<string, unknown>>;
18
- termsFailed: Record<string, Record<string, unknown>>;
19
- terms: Record<string, any>;
20
- taxonomyUIDs: string[];
13
+ createdTaxonomies: Record<string, unknown>;
14
+ failedTaxonomies: Record<string, unknown>;
15
+ createdTerms: Record<string, Record<string, unknown>>;
16
+ failedTerms: Record<string, Record<string, unknown>>;
21
17
  constructor({ importConfig, stackAPIClient }: ModuleClassParams);
22
18
  /**
23
19
  * @method start
@@ -39,25 +35,8 @@ export default class ImportTaxonomies extends BaseClass {
39
35
  serializeTaxonomy(apiOptions: ApiOptions): ApiOptions;
40
36
  /**
41
37
  * create taxonomies success and fail in (mapper/taxonomies)
42
- * @method createTaxonomySuccessAndFailedFile
43
- */
44
- createTaxonomySuccessAndFailedFile(): void;
45
- /**
46
- * create terms and enter success & failure related data into terms mapper file
47
- * @method importTerms
48
- * @async
49
- * @returns {Promise<any>} Promise<any>
50
- */
51
- importTerms(): Promise<any>;
52
- /**
53
- * @method serializeTerms
54
- * @param {ApiOptions} apiOptions ApiOptions
55
- * @returns {ApiOptions} ApiOptions
56
- */
57
- serializeTerms(apiOptions: ApiOptions): ApiOptions;
58
- /**
59
38
  * create terms success and fail in (mapper/taxonomies/terms)
60
- * @method createTermSuccessAndFailedFile
39
+ * @method createSuccessAndFailedFile
61
40
  */
62
- createTermSuccessAndFailedFile(): void;
41
+ createSuccessAndFailedFile(): void;
63
42
  }
@@ -1,8 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
- const keys_1 = tslib_1.__importDefault(require("lodash/keys"));
5
- const pick_1 = tslib_1.__importDefault(require("lodash/pick"));
6
4
  const node_path_1 = require("node:path");
7
5
  const values_1 = tslib_1.__importDefault(require("lodash/values"));
8
6
  const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
@@ -11,18 +9,14 @@ const utils_1 = require("../../utils");
11
9
  class ImportTaxonomies extends base_class_1.default {
12
10
  constructor({ importConfig, stackAPIClient }) {
13
11
  super({ importConfig, stackAPIClient });
14
- this.taxonomiesSuccess = {};
15
- this.taxonomiesFailed = {};
16
- this.termsSuccess = {};
17
- this.termsFailed = {};
18
- this.terms = [];
19
- this.taxonomyUIDs = [];
12
+ this.createdTaxonomies = {};
13
+ this.failedTaxonomies = {};
14
+ this.createdTerms = {};
15
+ this.failedTerms = {};
20
16
  this.taxonomiesConfig = importConfig.modules.taxonomies;
21
- this.termsConfig = importConfig.modules.terms;
22
17
  this.taxonomiesMapperDirPath = (0, node_path_1.join)(importConfig.backupDir, 'mapper', 'taxonomies');
23
18
  this.termsMapperDirPath = (0, node_path_1.join)(this.taxonomiesMapperDirPath, 'terms');
24
19
  this.taxonomiesFolderPath = (0, node_path_1.join)(importConfig.backupDir, this.taxonomiesConfig.dirName);
25
- this.termsFolderPath = (0, node_path_1.join)(this.taxonomiesFolderPath, this.termsConfig.dirName);
26
20
  this.taxSuccessPath = (0, node_path_1.join)(this.taxonomiesMapperDirPath, 'success.json');
27
21
  this.taxFailsPath = (0, node_path_1.join)(this.taxonomiesMapperDirPath, 'fails.json');
28
22
  this.termsSuccessPath = (0, node_path_1.join)(this.termsMapperDirPath, 'success.json');
@@ -45,16 +39,10 @@ class ImportTaxonomies extends base_class_1.default {
45
39
  //Step 2 create taxonomies & terms mapper directory
46
40
  await utils_1.fsUtil.makeDirectory(this.taxonomiesMapperDirPath);
47
41
  await utils_1.fsUtil.makeDirectory(this.termsMapperDirPath);
48
- //Step 3 import taxonomy and create success & failure file
42
+ // Step 3 import taxonomies
49
43
  await this.importTaxonomies();
50
- this.createTaxonomySuccessAndFailedFile();
51
- if (!utils_1.fileHelper.fileExistsSync(this.termsFolderPath)) {
52
- (0, utils_1.log)(this.importConfig, `No such file or directory - '${this.termsFolderPath}'`, 'error');
53
- return;
54
- }
55
- //Step 4 import terms and create success & failure file
56
- await this.importTerms();
57
- this.createTermSuccessAndFailedFile();
44
+ //Step 4 create taxonomy & related terms success & failure file
45
+ this.createSuccessAndFailedFile();
58
46
  (0, utils_1.log)(this.importConfig, 'Taxonomies imported successfully!', 'success');
59
47
  }
60
48
  /**
@@ -69,24 +57,25 @@ class ImportTaxonomies extends base_class_1.default {
69
57
  return;
70
58
  }
71
59
  const apiContent = (0, values_1.default)(this.taxonomies);
72
- this.taxonomyUIDs = (0, keys_1.default)(this.taxonomies);
73
- const onSuccess = ({ response }) => {
74
- const { uid } = response;
75
- this.taxonomiesSuccess[uid] = (0, pick_1.default)(response, ['name', 'description']);
76
- (0, utils_1.log)(this.importConfig, `Taxonomy '${uid}' imported successfully!`, 'success');
60
+ const onSuccess = ({ apiData }) => {
61
+ var _a;
62
+ const taxonomyUID = (_a = apiData === null || apiData === void 0 ? void 0 : apiData.taxonomy) === null || _a === void 0 ? void 0 : _a.uid;
63
+ this.createdTaxonomies[taxonomyUID] = apiData === null || apiData === void 0 ? void 0 : apiData.taxonomy;
64
+ this.createdTerms[taxonomyUID] = apiData === null || apiData === void 0 ? void 0 : apiData.terms;
65
+ (0, utils_1.log)(this.importConfig, `Taxonomy '${taxonomyUID}' imported successfully!`, 'success');
77
66
  };
78
67
  const onReject = ({ error, apiData }) => {
79
- var _a;
80
- const err = (error === null || error === void 0 ? void 0 : error.message) ? JSON.parse(error.message) : error;
81
- const { uid } = apiData;
82
- if ((_a = err === null || err === void 0 ? void 0 : err.errors) === null || _a === void 0 ? void 0 : _a.taxonomy) {
83
- this.taxonomiesFailed[uid] = apiData;
84
- (0, utils_1.log)(this.importConfig, `Taxonomy '${uid}' failed to be import! ${err.errors.taxonomy}`, 'error');
68
+ var _a, _b, _c;
69
+ const taxonomyUID = (_a = apiData === null || apiData === void 0 ? void 0 : apiData.taxonomy) === null || _a === void 0 ? void 0 : _a.uid;
70
+ if ((error === null || error === void 0 ? void 0 : error.errorMessage) || (error === null || error === void 0 ? void 0 : error.message)) {
71
+ const errorMsg = (error === null || error === void 0 ? void 0 : error.errorMessage) || ((_b = error === null || error === void 0 ? void 0 : error.errors) === null || _b === void 0 ? void 0 : _b.taxonomy) || ((_c = error === null || error === void 0 ? void 0 : error.errors) === null || _c === void 0 ? void 0 : _c.term) || (error === null || error === void 0 ? void 0 : error.message);
72
+ (0, utils_1.log)(this.importConfig, `Taxonomy '${taxonomyUID}' failed to be import! ${errorMsg}`, 'error');
85
73
  }
86
74
  else {
87
- this.taxonomiesFailed[apiData.uid] = apiData;
88
- (0, utils_1.log)(this.importConfig, `Taxonomy '${uid}' failed to be import! ${(0, utils_1.formatError)(error)}`, 'error');
75
+ (0, utils_1.log)(this.importConfig, `Taxonomy '${taxonomyUID}' failed to be import! ${(0, utils_1.formatError)(error)}`, 'error');
89
76
  }
77
+ this.failedTaxonomies[taxonomyUID] = apiData === null || apiData === void 0 ? void 0 : apiData.taxonomy;
78
+ this.failedTerms[taxonomyUID] = apiData === null || apiData === void 0 ? void 0 : apiData.terms;
90
79
  };
91
80
  await this.makeConcurrentCall({
92
81
  apiContent,
@@ -95,7 +84,7 @@ class ImportTaxonomies extends base_class_1.default {
95
84
  serializeData: this.serializeTaxonomy.bind(this),
96
85
  reject: onReject,
97
86
  resolve: onSuccess,
98
- entity: 'create-taxonomies',
87
+ entity: 'import-taxonomy',
99
88
  includeParamOnCompletion: true,
100
89
  },
101
90
  concurrencyLimit: this.importConfig.concurrency || this.importConfig.fetchConcurrency || 1,
@@ -107,110 +96,35 @@ class ImportTaxonomies extends base_class_1.default {
107
96
  * @returns {ApiOptions} ApiOptions
108
97
  */
109
98
  serializeTaxonomy(apiOptions) {
110
- const { apiData: taxonomy } = apiOptions;
111
- apiOptions.apiData = taxonomy;
112
- return apiOptions;
113
- }
114
- /**
115
- * create taxonomies success and fail in (mapper/taxonomies)
116
- * @method createTaxonomySuccessAndFailedFile
117
- */
118
- createTaxonomySuccessAndFailedFile() {
119
- if (this.taxonomiesSuccess !== undefined && !(0, isEmpty_1.default)(this.taxonomiesSuccess)) {
120
- utils_1.fsUtil.writeFile(this.taxSuccessPath, this.taxonomiesSuccess);
121
- }
122
- if (this.taxonomiesFailed !== undefined && !(0, isEmpty_1.default)(this.taxonomiesFailed)) {
123
- utils_1.fsUtil.writeFile(this.taxFailsPath, this.taxonomiesFailed);
124
- }
125
- }
126
- /**
127
- * create terms and enter success & failure related data into terms mapper file
128
- * @method importTerms
129
- * @async
130
- * @returns {Promise<any>} Promise<any>
131
- */
132
- async importTerms() {
133
- var _a, _b;
134
- if (!((_a = this.taxonomyUIDs) === null || _a === void 0 ? void 0 : _a.length)) {
135
- return;
136
- }
137
- const onSuccess = ({ response, apiData: { taxonomy_uid } = { taxonomy_uid: null } }) => {
138
- var _a;
139
- const { uid } = response;
140
- if (!((_a = this.termsSuccess) === null || _a === void 0 ? void 0 : _a[taxonomy_uid]))
141
- this.termsSuccess[taxonomy_uid] = {};
142
- this.termsSuccess[taxonomy_uid][uid] = (0, pick_1.default)(response, ['name']);
143
- (0, utils_1.log)(this.importConfig, `Term '${uid}' imported successfully!`, 'success');
144
- };
145
- const onReject = ({ error, apiData }) => {
146
- var _a, _b;
147
- const { taxonomy_uid, uid } = apiData;
148
- if (!((_a = this.termsFailed) === null || _a === void 0 ? void 0 : _a[taxonomy_uid]))
149
- this.termsFailed[taxonomy_uid] = {};
150
- const err = (error === null || error === void 0 ? void 0 : error.message) ? JSON.parse(error.message) : error;
151
- if ((_b = err === null || err === void 0 ? void 0 : err.errors) === null || _b === void 0 ? void 0 : _b.term) {
152
- this.termsFailed[taxonomy_uid][uid] = apiData;
153
- (0, utils_1.log)(this.importConfig, `Term '${uid}' failed to be import! ${err.errors.term}`, 'error');
154
- }
155
- else {
156
- this.termsFailed[taxonomy_uid][uid] = apiData;
157
- (0, utils_1.log)(this.importConfig, `Term '${uid}' failed to be import! ${(0, utils_1.formatError)(error)}`, 'error');
158
- }
159
- };
160
- for (const taxUID of this.taxonomyUIDs) {
161
- //read terms from respective taxonomy
162
- this.terms = utils_1.fsUtil.readFile((0, node_path_1.join)(this.termsFolderPath, `${taxUID}-${this.termsConfig.fileName}`), true);
163
- if ((_b = this.terms) === null || _b === void 0 ? void 0 : _b.length) {
164
- const apiContent = this.terms;
165
- await this.makeConcurrentCall({
166
- apiContent,
167
- processName: 'import terms',
168
- apiParams: {
169
- serializeData: this.serializeTerms.bind(this),
170
- reject: onReject,
171
- resolve: onSuccess,
172
- entity: 'create-terms',
173
- includeParamOnCompletion: true,
174
- },
175
- concurrencyLimit: this.importConfig.concurrency || this.importConfig.fetchConcurrency || 1,
176
- }, undefined, false);
177
- }
178
- }
179
- }
180
- /**
181
- * @method serializeTerms
182
- * @param {ApiOptions} apiOptions ApiOptions
183
- * @returns {ApiOptions} ApiOptions
184
- */
185
- serializeTerms(apiOptions) {
186
- var _a, _b;
187
- const { apiData: term } = apiOptions;
188
- const { parent_uid, taxonomy_uid } = term;
189
- //check whether parent term exists or not in taxonomy
190
- if (parent_uid !== null) {
191
- if (!((_b = (_a = this.termsSuccess) === null || _a === void 0 ? void 0 : _a[taxonomy_uid]) === null || _b === void 0 ? void 0 : _b[parent_uid])) {
192
- (0, utils_1.log)(this.importConfig, `Parent term '${term === null || term === void 0 ? void 0 : term.parent_uid}' does not exist! Skipping '${term.uid}' creation to avoid further issues.`, 'info');
193
- apiOptions.apiData = undefined;
194
- }
195
- else {
196
- apiOptions.apiData = term;
197
- }
99
+ const { apiData } = apiOptions;
100
+ const filePath = (0, node_path_1.join)(this.taxonomiesFolderPath, `${apiData === null || apiData === void 0 ? void 0 : apiData.uid}.json`);
101
+ if (utils_1.fileHelper.fileExistsSync(filePath)) {
102
+ const taxonomyDetails = utils_1.fsUtil.readFile(filePath, true);
103
+ apiOptions.apiData = { filePath, taxonomy: taxonomyDetails === null || taxonomyDetails === void 0 ? void 0 : taxonomyDetails.taxonomy, terms: taxonomyDetails === null || taxonomyDetails === void 0 ? void 0 : taxonomyDetails.terms };
198
104
  }
199
105
  else {
200
- apiOptions.apiData = term;
106
+ (0, utils_1.log)(this.importConfig, `No such file - ${filePath}`, 'error');
107
+ apiOptions.apiData = undefined;
201
108
  }
202
109
  return apiOptions;
203
110
  }
204
111
  /**
112
+ * create taxonomies success and fail in (mapper/taxonomies)
205
113
  * create terms success and fail in (mapper/taxonomies/terms)
206
- * @method createTermSuccessAndFailedFile
114
+ * @method createSuccessAndFailedFile
207
115
  */
208
- createTermSuccessAndFailedFile() {
209
- if (this.termsSuccess !== undefined && !(0, isEmpty_1.default)(this.termsSuccess)) {
210
- utils_1.fsUtil.writeFile(this.termsSuccessPath, this.termsSuccess);
116
+ createSuccessAndFailedFile() {
117
+ if (this.createdTaxonomies !== undefined && !(0, isEmpty_1.default)(this.createdTaxonomies)) {
118
+ utils_1.fsUtil.writeFile(this.taxSuccessPath, this.createdTaxonomies);
119
+ }
120
+ if (this.failedTaxonomies !== undefined && !(0, isEmpty_1.default)(this.failedTaxonomies)) {
121
+ utils_1.fsUtil.writeFile(this.taxFailsPath, this.failedTaxonomies);
122
+ }
123
+ if (this.createdTerms !== undefined && !(0, isEmpty_1.default)(this.createdTerms)) {
124
+ utils_1.fsUtil.writeFile(this.termsSuccessPath, this.createdTerms);
211
125
  }
212
- if (this.termsFailed !== undefined && !(0, isEmpty_1.default)(this.termsFailed)) {
213
- utils_1.fsUtil.writeFile(this.termsFailsPath, this.termsFailed);
126
+ if (this.failedTerms !== undefined && !(0, isEmpty_1.default)(this.failedTerms)) {
127
+ utils_1.fsUtil.writeFile(this.termsFailsPath, this.failedTerms);
214
128
  }
215
129
  }
216
130
  }
@@ -117,11 +117,6 @@ export default interface DefaultConfig {
117
117
  fileName: string;
118
118
  dependencies?: Modules[];
119
119
  };
120
- terms: {
121
- dirName: string;
122
- fileName: string;
123
- dependencies?: Modules[];
124
- };
125
120
  };
126
121
  languagesCode: string[];
127
122
  apis: {
@@ -46,6 +46,7 @@ export default interface ImportConfig extends DefaultConfig, ExternalConfig {
46
46
  replaceExisting?: boolean;
47
47
  skipExisting?: boolean;
48
48
  skipAudit?: boolean;
49
+ stackName?: string;
49
50
  }
50
51
  type branch = {
51
52
  uid: string;
@@ -65,12 +65,12 @@ export interface TaxonomiesConfig {
65
65
  fileName: string;
66
66
  dependencies?: Modules[];
67
67
  }
68
- export interface TermsConfig {
69
- dirName: string;
70
- fileName: string;
71
- dependencies?: Modules[];
72
- }
73
68
  export { default as DefaultConfig } from './default-config';
74
69
  export { default as ImportConfig } from './import-config';
75
70
  export * from './entries';
76
71
  export * from './marketplace-app';
72
+ export type ExtensionType = {
73
+ uid: string;
74
+ scope: Record<string, unknown>;
75
+ title: string;
76
+ };
@@ -10,6 +10,7 @@ const file_helper_1 = require("./file-helper");
10
10
  const interactive_1 = require("./interactive");
11
11
  const login_handler_1 = tslib_1.__importDefault(require("./login-handler"));
12
12
  const setupConfig = async (importCmdFlags) => {
13
+ var _a;
13
14
  let config = (0, merge_1.default)({}, config_1.default);
14
15
  // setup the config
15
16
  if (importCmdFlags['config']) {
@@ -33,7 +34,7 @@ const setupConfig = async (importCmdFlags) => {
33
34
  }
34
35
  const managementTokenAlias = importCmdFlags['management-token-alias'] || importCmdFlags['alias'];
35
36
  if (managementTokenAlias) {
36
- const { token, apiKey } = cli_utilities_1.configHandler.get(`tokens.${managementTokenAlias}`);
37
+ const { token, apiKey } = (_a = cli_utilities_1.configHandler.get(`tokens.${managementTokenAlias}`)) !== null && _a !== void 0 ? _a : {};
37
38
  config.management_token = token;
38
39
  config.apiKey = apiKey;
39
40
  if (!config.management_token) {
@@ -1,6 +1,5 @@
1
1
  export declare const askContentDir: () => Promise<string>;
2
2
  export declare const askAPIKey: () => Promise<string>;
3
- export declare const askDeveloperHubUrl: (regionName: string) => Promise<string>;
4
3
  export declare const askEncryptionKey: (defaultValue: unknown) => Promise<string>;
5
4
  export declare const askAppName: (app: any, appSuffix: number) => Promise<string>;
6
5
  export declare const getAppName: (name: string, appSuffix?: number) => string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.selectConfiguration = exports.getAppName = exports.askAppName = exports.askEncryptionKey = exports.askDeveloperHubUrl = exports.askAPIKey = exports.askContentDir = void 0;
3
+ exports.selectConfiguration = exports.getAppName = exports.askAppName = exports.askEncryptionKey = exports.askAPIKey = exports.askContentDir = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const cli_utilities_1 = require("@contentstack/cli-utilities");
6
6
  const path = tslib_1.__importStar(require("path"));
@@ -23,19 +23,6 @@ const askAPIKey = async () => {
23
23
  });
24
24
  };
25
25
  exports.askAPIKey = askAPIKey;
26
- const askDeveloperHubUrl = async (regionName) => {
27
- return await cli_utilities_1.cliux.inquire({
28
- type: 'input',
29
- name: 'name',
30
- validate: (url) => {
31
- if (!url)
32
- return "Developer-hub URL can't be empty.";
33
- return true;
34
- },
35
- message: `Enter the developer-hub base URL for the ${regionName} region -`,
36
- });
37
- };
38
- exports.askDeveloperHubUrl = askDeveloperHubUrl;
39
26
  const askEncryptionKey = async (defaultValue) => {
40
27
  return await cli_utilities_1.cliux.inquire({
41
28
  type: 'input',
@@ -11,8 +11,7 @@ const cli_utilities_1 = require("@contentstack/cli-utilities");
11
11
  const logger_1 = require("./logger");
12
12
  const log_1 = require("../utils/log");
13
13
  const utils_1 = require("../utils");
14
- const interactive_1 = require("./interactive");
15
- const interactive_2 = require("../utils/interactive");
14
+ const interactive_1 = require("../utils/interactive");
16
15
  const getAllStackSpecificApps = async (config, skip = 0, listOfApps = []) => {
17
16
  const appSdk = await (0, cli_utilities_1.marketplaceSDKClient)({
18
17
  host: config.developerHubBaseUrl.split('://').pop(),
@@ -42,12 +41,7 @@ const getAllStackSpecificApps = async (config, skip = 0, listOfApps = []) => {
42
41
  };
43
42
  exports.getAllStackSpecificApps = getAllStackSpecificApps;
44
43
  const getDeveloperHubUrl = async (config) => {
45
- const { cma, name } = cli_utilities_1.configHandler.get('region') || {};
46
- let developerHubBaseUrl = config.developerHubUrls[cma];
47
- if (!developerHubBaseUrl) {
48
- developerHubBaseUrl = await (0, interactive_1.askDeveloperHubUrl)(name);
49
- }
50
- return developerHubBaseUrl.startsWith('http') ? developerHubBaseUrl : `https://${developerHubBaseUrl}`;
44
+ return (0, cli_utilities_1.createDeveloperHubUrl)(config.host);
51
45
  };
52
46
  exports.getDeveloperHubUrl = getDeveloperHubUrl;
53
47
  const getOrgUid = async (config) => {
@@ -77,8 +71,8 @@ const getConfirmationToCreateApps = async (privateApps, config) => {
77
71
  exports.getConfirmationToCreateApps = getConfirmationToCreateApps;
78
72
  const handleNameConflict = async (app, appSuffix, config) => {
79
73
  const appName = config.forceStopMarketplaceAppsPrompt
80
- ? (0, interactive_2.getAppName)(app.name, appSuffix)
81
- : await (0, interactive_2.askAppName)(app, appSuffix);
74
+ ? (0, interactive_1.getAppName)(app.name, appSuffix)
75
+ : await (0, interactive_1.askAppName)(app, appSuffix);
82
76
  app.name = appName;
83
77
  return app;
84
78
  };
@@ -124,7 +118,7 @@ const ifAppAlreadyExist = async (app, currentStackApp, config) => {
124
118
  cli_utilities_1.cliux.print(`\nWARNING!!! The ${name} 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.\n`, { color: 'yellow' });
125
119
  const configOption = config.forceStopMarketplaceAppsPrompt
126
120
  ? 'Update it with the new configuration.'
127
- : await (0, interactive_2.selectConfiguration)();
121
+ : await (0, interactive_1.selectConfiguration)();
128
122
  if (configOption === 'Exit') {
129
123
  process.exit();
130
124
  }
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.lookUpTerms = exports.lookUpTaxonomy = void 0;
4
+ const tslib_1 = require("tslib");
4
5
  /**
5
6
  * taxonomy lookup
6
7
  */
8
+ const find_1 = tslib_1.__importDefault(require("lodash/find"));
7
9
  const _1 = require("./");
8
10
  /**
9
11
  * check and remove if referenced taxonomy doesn't exists in stack
@@ -66,7 +68,13 @@ const lookUpTerms = function (ctSchema, entry, taxonomiesAndTermData, importConf
66
68
  if (ctSchema[index].data_type === 'taxonomy') {
67
69
  const taxonomyFieldData = entry[ctSchema[index].uid];
68
70
  const updatedTaxonomyData = verifyAndRemoveTerms(taxonomyFieldData, taxonomiesAndTermData, importConfig);
69
- entry[ctSchema[index].uid] = updatedTaxonomyData;
71
+ if (updatedTaxonomyData === null || updatedTaxonomyData === void 0 ? void 0 : updatedTaxonomyData.length) {
72
+ entry[ctSchema[index].uid] = updatedTaxonomyData;
73
+ }
74
+ else {
75
+ //Delete taxonomy from entry if taxonomy field removed from CT
76
+ delete entry[ctSchema[index].uid];
77
+ }
70
78
  }
71
79
  }
72
80
  };
@@ -85,7 +93,8 @@ const verifyAndRemoveTerms = function (taxonomyFieldData, taxonomiesAndTermData,
85
93
  const termUID = taxonomyData === null || taxonomyData === void 0 ? void 0 : taxonomyData.term_uid;
86
94
  if (taxonomiesAndTermData === undefined ||
87
95
  !taxonomiesAndTermData.hasOwnProperty(taxUID) ||
88
- (taxonomiesAndTermData.hasOwnProperty(taxUID) && !taxonomiesAndTermData[taxUID].hasOwnProperty(termUID))) {
96
+ (taxonomiesAndTermData.hasOwnProperty(taxUID) &&
97
+ !(0, find_1.default)(taxonomiesAndTermData[taxUID], (term) => (term === null || term === void 0 ? void 0 : term.uid) === termUID))) {
89
98
  // remove term from taxonomies field data with warning if respective term doesn't exists
90
99
  (0, _1.log)(importConfig, `Term '${termUID}' does not exist. Removing it from taxonomy - '${taxUID}'`, 'warn');
91
100
  taxonomyFieldData.splice(index, 1);
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.13.2",
2
+ "version": "1.14.0",
3
3
  "commands": {
4
4
  "cm:stacks:import": {
5
5
  "id": "cm:stacks:import",
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@contentstack/cli-cm-import",
3
3
  "description": "Contentstack CLI plugin to import content into stack",
4
- "version": "1.13.2",
4
+ "version": "1.14.0",
5
5
  "author": "Contentstack",
6
6
  "bugs": "https://github.com/contentstack/cli/issues",
7
7
  "dependencies": {
8
- "@contentstack/cli-audit": "^1.3.3",
8
+ "@contentstack/cli-audit": "~1.4.0",
9
9
  "@contentstack/cli-command": "~1.2.16",
10
- "@contentstack/cli-utilities": "~1.5.11",
11
- "@contentstack/management": "~1.13.0",
10
+ "@contentstack/cli-utilities": "~1.5.12",
11
+ "@contentstack/management": "~1.15.3",
12
12
  "@oclif/core": "^2.9.3",
13
13
  "big-json": "^3.2.0",
14
14
  "bluebird": "^3.7.2",
@@ -25,7 +25,7 @@
25
25
  "winston": "^3.7.2"
26
26
  },
27
27
  "devDependencies": {
28
- "@oclif/test": "^1.2.6",
28
+ "@oclif/test": "^2.5.6",
29
29
  "@types/big-json": "^3.2.0",
30
30
  "@types/bluebird": "^3.5.38",
31
31
  "@types/chai": "^4.2.18",
@@ -46,7 +46,7 @@
46
46
  "oclif": "^3.8.1",
47
47
  "rimraf": "^2.7.1",
48
48
  "sinon": "^11.1.1",
49
- "tmp": "^0.2.1",
49
+ "tmp": "^0.2.2",
50
50
  "ts-node": "^10.9.1",
51
51
  "typescript": "^4.9.3"
52
52
  },