@contentstack/cli-cm-import 1.10.0 → 1.11.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.10.0 linux-x64 node-v18.18.2
50
+ @contentstack/cli-cm-import/1.11.0 linux-x64 node-v18.18.2
51
51
  $ csdx --help [COMMAND]
52
52
  USAGE
53
53
  $ csdx COMMAND
@@ -4,6 +4,7 @@ const tslib_1 = require("tslib");
4
4
  const node_path_1 = tslib_1.__importDefault(require("node:path"));
5
5
  const cli_command_1 = require("@contentstack/cli-command");
6
6
  const cli_utilities_1 = require("@contentstack/cli-utilities");
7
+ const log_1 = require("../../../utils/log");
7
8
  const import_1 = require("../../../import");
8
9
  const utils_1 = require("../../../utils");
9
10
  class ImportCommand extends cli_command_1.Command {
@@ -25,6 +26,7 @@ class ImportCommand extends cli_command_1.Command {
25
26
  (0, utils_1.log)(importConfig, `The log has been stored at '${node_path_1.default.join(importConfig.backupDir, 'logs', 'import')}'`, 'success');
26
27
  }
27
28
  catch (error) {
29
+ (0, log_1.trace)(error, 'error', true);
28
30
  (0, utils_1.log)({ data: backupDir }, `Failed to import stack content - ${(0, utils_1.formatError)(error)}`, 'error');
29
31
  (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');
30
32
  }
@@ -18,7 +18,6 @@ const config = {
18
18
  'https://eu-api.contentstack.com': 'https://eu-developerhub-api.contentstack.com',
19
19
  'https://azure-na-api.contentstack.com': 'https://azure-na-developerhub-api.contentstack.com',
20
20
  'https://azure-eu-api.contentstack.com': 'https://azure-eu-developerhub-api.contentstack.com',
21
- 'https://stag-api.csnonprod.com': 'https://stag-developerhub-api.csnonprod.com',
22
21
  },
23
22
  modules: {
24
23
  apiConcurrency: 5,
@@ -26,6 +25,7 @@ const config = {
26
25
  'locales',
27
26
  'environments',
28
27
  'assets',
28
+ 'taxonomies',
29
29
  'extensions',
30
30
  'marketplace-apps',
31
31
  'global-fields',
@@ -142,6 +142,14 @@ const config = {
142
142
  dirName: 'marketplace_apps',
143
143
  fileName: 'marketplace_apps.json',
144
144
  },
145
+ taxonomies: {
146
+ dirName: 'taxonomies',
147
+ fileName: 'taxonomies.json',
148
+ },
149
+ terms: {
150
+ dirName: 'terms',
151
+ fileName: 'terms.json',
152
+ },
145
153
  },
146
154
  languagesCode: [
147
155
  'af-za',
@@ -380,5 +388,6 @@ const config = {
380
388
  getEncryptionKeyMaxRetry: 3,
381
389
  // useBackedupDir: '',
382
390
  // backupConcurrency: 10,
391
+ onlyTSModules: ['taxonomies'],
383
392
  };
384
393
  exports.default = config;
@@ -2,9 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  const cli_utilities_1 = require("@contentstack/cli-utilities");
5
- const utils_1 = require("../utils");
6
5
  const modules_1 = tslib_1.__importDefault(require("./modules"));
7
6
  const modules_js_1 = tslib_1.__importDefault(require("./modules-js"));
7
+ const utils_1 = require("../utils");
8
8
  class ModuleImporter {
9
9
  constructor(managementAPIClient, importConfig) {
10
10
  this.managementAPIClient = managementAPIClient;
@@ -43,6 +43,8 @@ class ModuleImporter {
43
43
  // To support the old config
44
44
  this.importConfig.data = backupDir;
45
45
  }
46
+ // NOTE init log
47
+ (0, utils_1.initLogger)(this.importConfig);
46
48
  await (0, utils_1.sanitizeStack)(this.stackAPIClient);
47
49
  return this.import();
48
50
  }
@@ -58,7 +60,7 @@ class ModuleImporter {
58
60
  (0, utils_1.log)(this.importConfig, `Starting import of ${moduleName} module`, 'info');
59
61
  // import the modules by name
60
62
  // calls the module runner which inturn calls the module itself
61
- // Todo: Implement a mechanism to determine whether module is new or old
63
+ // NOTE: Implement a mechanism to determine whether module is new or old
62
64
  if (this.importConfig.contentVersion === 2) {
63
65
  return (0, modules_1.default)({
64
66
  stackAPIClient: this.stackAPIClient,
@@ -66,11 +68,16 @@ class ModuleImporter {
66
68
  moduleName,
67
69
  });
68
70
  }
69
- return (0, modules_js_1.default)({
70
- stackAPIClient: this.stackAPIClient,
71
- importConfig: this.importConfig,
72
- moduleName,
73
- });
71
+ else {
72
+ //NOTE - new modules support only ts
73
+ if (this.importConfig.onlyTSModules.indexOf(moduleName) === -1) {
74
+ return (0, modules_js_1.default)({
75
+ stackAPIClient: this.stackAPIClient,
76
+ importConfig: this.importConfig,
77
+ moduleName,
78
+ });
79
+ }
80
+ }
74
81
  }
75
82
  async importAllModules() {
76
83
  // use the algorithm to determine the parallel and sequential execution of modules
@@ -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';
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';
7
7
  export type ApiOptions = {
8
8
  uid?: string;
9
9
  url?: string;
@@ -255,6 +255,17 @@ class BaseClass {
255
255
  .delete({ locale: additionalInfo.locale })
256
256
  .then(onSuccess)
257
257
  .catch(onReject);
258
+ case 'create-taxonomies':
259
+ return this.stack.taxonomy().create({ taxonomy: apiData }).then(onSuccess).catch(onReject);
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);
268
+ }
258
269
  default:
259
270
  return Promise.resolve();
260
271
  }
@@ -30,6 +30,8 @@ export default class ContentTypesImport extends BaseClass {
30
30
  private installedExtensions;
31
31
  private cTsConfig;
32
32
  private gFsConfig;
33
+ private taxonomiesPath;
34
+ taxonomies: Record<string, unknown>;
33
35
  constructor({ importConfig, stackAPIClient }: ModuleClassParams);
34
36
  start(): Promise<any>;
35
37
  seedCTs(): Promise<any>;
@@ -38,6 +38,7 @@ class ContentTypesImport extends base_class_1.default {
38
38
  this.gFs = [];
39
39
  this.createdGFs = [];
40
40
  this.pendingGFs = [];
41
+ this.taxonomiesPath = path.join(importConfig.data, 'mapper/taxonomies', 'success.json');
41
42
  }
42
43
  async start() {
43
44
  /**
@@ -54,6 +55,7 @@ class ContentTypesImport extends base_class_1.default {
54
55
  }
55
56
  await utils_1.fsUtil.makeDirectory(this.cTsMapperPath);
56
57
  this.installedExtensions = ((await utils_1.fsUtil.readFile(this.marketplaceAppMapperPath)) || { extension_uid: {} }).extension_uid;
58
+ this.taxonomies = utils_1.fsUtil.readFile(this.taxonomiesPath);
57
59
  await this.seedCTs();
58
60
  (0, utils_1.log)(this.importConfig, 'Created content types', 'success');
59
61
  await this.updateCTs();
@@ -108,7 +110,7 @@ class ContentTypesImport extends base_class_1.default {
108
110
  }
109
111
  async updateCTs() {
110
112
  const onSuccess = ({ response: contentType, apiData: { uid } }) => {
111
- (0, utils_1.log)(this.importConfig, `${uid} updated with references`, 'success');
113
+ (0, utils_1.log)(this.importConfig, `'${uid}' updated with references`, 'success');
112
114
  };
113
115
  const onReject = ({ error, apiData: { uid } }) => {
114
116
  (0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
@@ -141,6 +143,8 @@ class ContentTypesImport extends base_class_1.default {
141
143
  }
142
144
  this.fieldRules.push(contentType.uid);
143
145
  }
146
+ //will remove taxonomy if taxonomy doesn't exists in stack
147
+ (0, utils_1.lookUpTaxonomy)(this.importConfig, contentType.schema, this.taxonomies);
144
148
  (0, utils_1.lookupExtension)(this.importConfig, contentType.schema, this.importConfig.preserveStackVersion, this.installedExtensions);
145
149
  const contentTypePayload = this.stack.contentType(contentType.uid);
146
150
  Object.assign(contentTypePayload, (0, lodash_1.cloneDeep)(contentType));
@@ -34,6 +34,8 @@ export default class EntriesImport extends BaseClass {
34
34
  private entriesUidMapper;
35
35
  private envs;
36
36
  private autoCreatedEntries;
37
+ private taxonomiesPath;
38
+ taxonomies: Record<string, unknown>;
37
39
  constructor({ importConfig, stackAPIClient }: ModuleClassParams);
38
40
  start(): Promise<any>;
39
41
  disableMandatoryCTReferences(): Promise<void>;
@@ -23,6 +23,7 @@ class EntriesImport extends base_class_1.default {
23
23
  this.uniqueUidMapperPath = path.join(this.entriesMapperPath, 'unique-mapping.json');
24
24
  this.modifiedCTsPath = path.join(this.entriesMapperPath, 'modified-schemas.json');
25
25
  this.marketplaceAppMapperPath = path.join(this.importConfig.data, 'mapper', 'marketplace_apps', 'uid-mapping.json');
26
+ this.taxonomiesPath = path.join(this.importConfig.data, 'mapper', 'taxonomies', 'terms', 'success.json');
26
27
  this.entriesConfig = importConfig.modules.entries;
27
28
  this.entriesPath = path.resolve(importConfig.data, this.entriesConfig.dirName);
28
29
  this.cTsPath = path.resolve(importConfig.data, importConfig.modules['content-types'].dirName);
@@ -47,6 +48,7 @@ class EntriesImport extends base_class_1.default {
47
48
  this.installedExtensions = ((await utils_1.fsUtil.readFile(this.marketplaceAppMapperPath)) || { extension_uid: {} }).extension_uid;
48
49
  this.assetUidMapper = utils_1.fsUtil.readFile(this.assetUidMapperPath) || {};
49
50
  this.assetUrlMapper = utils_1.fsUtil.readFile(this.assetUrlMapperPath) || {};
51
+ this.taxonomies = utils_1.fsUtil.readFile(this.taxonomiesPath);
50
52
  utils_1.fsUtil.makeDirectory(this.entriesMapperPath);
51
53
  await this.disableMandatoryCTReferences();
52
54
  this.locales = (0, lodash_1.values)(utils_1.fsUtil.readFile(this.localesPath));
@@ -316,6 +318,8 @@ class EntriesImport extends base_class_1.default {
316
318
  if (this.jsonRteCTsWithRef.indexOf(cTUid) > -1) {
317
319
  entry = (0, utils_1.removeEntryRefsFromJSONRTE)(entry, contentType.schema);
318
320
  }
321
+ //will remove term if term doesn't exists in taxonomy
322
+ (0, utils_1.lookUpTerms)(contentType === null || contentType === void 0 ? void 0 : contentType.schema, entry, this.taxonomies, this.importConfig);
319
323
  // will replace all old asset uid/urls with new ones
320
324
  entry = (0, utils_1.lookupAssets)({
321
325
  content_type: contentType,
@@ -14,6 +14,7 @@ const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
14
14
  const toLower_1 = tslib_1.__importDefault(require("lodash/toLower"));
15
15
  const cli_utilities_1 = require("@contentstack/cli-utilities");
16
16
  const base_class_1 = tslib_1.__importDefault(require("./base-class"));
17
+ const log_1 = require("../../utils/log");
17
18
  const interactive_1 = require("../../utils/interactive");
18
19
  const utils_1 = require("../../utils");
19
20
  class ImportMarketplaceApps extends base_class_1.default {
@@ -54,7 +55,7 @@ class ImportMarketplaceApps extends base_class_1.default {
54
55
  this.developerHubBaseUrl = this.importConfig.developerHubBaseUrl || (await (0, utils_1.getDeveloperHubUrl)(this.importConfig));
55
56
  this.sdkClient = await (0, cli_utilities_1.managementSDKClient)({ endpoint: this.developerHubBaseUrl });
56
57
  this.appSdkAxiosInstance = await (0, cli_utilities_1.managementSDKClient)({
57
- host: this.developerHubBaseUrl.split('://').pop()
58
+ host: this.developerHubBaseUrl.split('://').pop(),
58
59
  });
59
60
  this.importConfig.org_uid = await (0, utils_1.getOrgUid)(this.importConfig);
60
61
  await this.setHttpClient();
@@ -223,6 +224,7 @@ class ImportMarketplaceApps extends base_class_1.default {
223
224
  return this.createPrivateApps(updatedApp, true, appSuffix + 1);
224
225
  }
225
226
  else {
227
+ (0, log_1.trace)(response, 'error', true);
226
228
  (0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(message), 'error');
227
229
  if (this.importConfig.forceStopMarketplaceAppsPrompt)
228
230
  return Promise.resolve();
@@ -308,13 +310,17 @@ class ImportMarketplaceApps extends base_class_1.default {
308
310
  })
309
311
  .then(({ data }) => {
310
312
  if (data === null || data === void 0 ? void 0 : data.message) {
313
+ (0, log_1.trace)(data, 'error', true);
311
314
  (0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(data.message), 'success');
312
315
  }
313
316
  else {
314
317
  (0, utils_1.log)(this.importConfig, `${app.manifest.name} app config updated successfully.!`, 'success');
315
318
  }
316
319
  })
317
- .catch((error) => (0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error'));
320
+ .catch((error) => {
321
+ (0, log_1.trace)(error, 'error', true);
322
+ (0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
323
+ });
318
324
  }
319
325
  }
320
326
  exports.default = ImportMarketplaceApps;
@@ -0,0 +1,63 @@
1
+ import BaseClass, { ApiOptions } from './base-class';
2
+ import { ModuleClassParams } from '../../types';
3
+ export default class ImportTaxonomies extends BaseClass {
4
+ private taxonomiesMapperDirPath;
5
+ private taxonomiesFolderPath;
6
+ private taxSuccessPath;
7
+ private taxFailsPath;
8
+ private taxonomiesConfig;
9
+ private taxonomies;
10
+ private termsFolderPath;
11
+ private termsMapperDirPath;
12
+ private termsConfig;
13
+ private termsSuccessPath;
14
+ 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[];
21
+ constructor({ importConfig, stackAPIClient }: ModuleClassParams);
22
+ /**
23
+ * @method start
24
+ * @returns {Promise<void>} Promise<void>
25
+ */
26
+ start(): Promise<void>;
27
+ /**
28
+ * create taxonomy and enter success & failure related data into taxonomies mapper file
29
+ * @method importTaxonomies
30
+ * @async
31
+ * @returns {Promise<any>} Promise<any>
32
+ */
33
+ importTaxonomies(): Promise<any>;
34
+ /**
35
+ * @method serializeTaxonomy
36
+ * @param {ApiOptions} apiOptions ApiOptions
37
+ * @returns {ApiOptions} ApiOptions
38
+ */
39
+ serializeTaxonomy(apiOptions: ApiOptions): ApiOptions;
40
+ /**
41
+ * 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
+ * create terms success and fail in (mapper/taxonomies/terms)
60
+ * @method createTermSuccessAndFailedFile
61
+ */
62
+ createTermSuccessAndFailedFile(): void;
63
+ }
@@ -0,0 +1,217 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
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
+ const node_path_1 = require("node:path");
7
+ const values_1 = tslib_1.__importDefault(require("lodash/values"));
8
+ const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
9
+ const base_class_1 = tslib_1.__importDefault(require("./base-class"));
10
+ const utils_1 = require("../../utils");
11
+ class ImportTaxonomies extends base_class_1.default {
12
+ constructor({ importConfig, stackAPIClient }) {
13
+ super({ importConfig, stackAPIClient });
14
+ this.taxonomiesSuccess = {};
15
+ this.taxonomiesFailed = {};
16
+ this.termsSuccess = {};
17
+ this.termsFailed = {};
18
+ this.terms = [];
19
+ this.taxonomyUIDs = [];
20
+ this.taxonomiesConfig = importConfig.modules.taxonomies;
21
+ this.termsConfig = importConfig.modules.terms;
22
+ this.taxonomiesMapperDirPath = (0, node_path_1.join)(importConfig.backupDir, 'mapper', 'taxonomies');
23
+ this.termsMapperDirPath = (0, node_path_1.join)(this.taxonomiesMapperDirPath, 'terms');
24
+ 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
+ this.taxSuccessPath = (0, node_path_1.join)(this.taxonomiesMapperDirPath, 'success.json');
27
+ this.taxFailsPath = (0, node_path_1.join)(this.taxonomiesMapperDirPath, 'fails.json');
28
+ this.termsSuccessPath = (0, node_path_1.join)(this.termsMapperDirPath, 'success.json');
29
+ this.termsFailsPath = (0, node_path_1.join)(this.termsMapperDirPath, 'fails.json');
30
+ }
31
+ /**
32
+ * @method start
33
+ * @returns {Promise<void>} Promise<void>
34
+ */
35
+ async start() {
36
+ (0, utils_1.log)(this.importConfig, 'Migrating taxonomies...', 'info');
37
+ //Step1 check folder exists or not
38
+ if (utils_1.fileHelper.fileExistsSync(this.taxonomiesFolderPath)) {
39
+ this.taxonomies = utils_1.fsUtil.readFile((0, node_path_1.join)(this.taxonomiesFolderPath, 'taxonomies.json'), true);
40
+ }
41
+ else {
42
+ (0, utils_1.log)(this.importConfig, `No such file or directory - '${this.taxonomiesFolderPath}'`, 'error');
43
+ return;
44
+ }
45
+ //Step 2 create taxonomies & terms mapper directory
46
+ await utils_1.fsUtil.makeDirectory(this.taxonomiesMapperDirPath);
47
+ await utils_1.fsUtil.makeDirectory(this.termsMapperDirPath);
48
+ //Step 3 import taxonomy and create success & failure file
49
+ 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();
58
+ (0, utils_1.log)(this.importConfig, 'Taxonomies imported successfully!', 'success');
59
+ }
60
+ /**
61
+ * create taxonomy and enter success & failure related data into taxonomies mapper file
62
+ * @method importTaxonomies
63
+ * @async
64
+ * @returns {Promise<any>} Promise<any>
65
+ */
66
+ async importTaxonomies() {
67
+ if (this.taxonomies === undefined || (0, isEmpty_1.default)(this.taxonomies)) {
68
+ (0, utils_1.log)(this.importConfig, 'No Taxonomies Found!', 'info');
69
+ return;
70
+ }
71
+ 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');
77
+ };
78
+ 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');
85
+ }
86
+ 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');
89
+ }
90
+ };
91
+ await this.makeConcurrentCall({
92
+ apiContent,
93
+ processName: 'import taxonomies',
94
+ apiParams: {
95
+ serializeData: this.serializeTaxonomy.bind(this),
96
+ reject: onReject,
97
+ resolve: onSuccess,
98
+ entity: 'create-taxonomies',
99
+ includeParamOnCompletion: true,
100
+ },
101
+ concurrencyLimit: this.importConfig.concurrency || this.importConfig.fetchConcurrency || 1,
102
+ }, undefined, false);
103
+ }
104
+ /**
105
+ * @method serializeTaxonomy
106
+ * @param {ApiOptions} apiOptions ApiOptions
107
+ * @returns {ApiOptions} ApiOptions
108
+ */
109
+ 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
+ }
198
+ }
199
+ else {
200
+ apiOptions.apiData = term;
201
+ }
202
+ return apiOptions;
203
+ }
204
+ /**
205
+ * create terms success and fail in (mapper/taxonomies/terms)
206
+ * @method createTermSuccessAndFailedFile
207
+ */
208
+ createTermSuccessAndFailedFile() {
209
+ if (this.termsSuccess !== undefined && !(0, isEmpty_1.default)(this.termsSuccess)) {
210
+ utils_1.fsUtil.writeFile(this.termsSuccessPath, this.termsSuccess);
211
+ }
212
+ if (this.termsFailed !== undefined && !(0, isEmpty_1.default)(this.termsFailed)) {
213
+ utils_1.fsUtil.writeFile(this.termsFailsPath, this.termsFailed);
214
+ }
215
+ }
216
+ }
217
+ exports.default = ImportTaxonomies;
@@ -9,8 +9,9 @@ const path = require('path');
9
9
  const chalk = require('chalk');
10
10
  const mkdirp = require('mkdirp');
11
11
  const { cliux, HttpClient, NodeCrypto, managementSDKClient, isAuthenticated, HttpClientDecorator, OauthDecorator, } = require('@contentstack/cli-utilities');
12
- const { log, fileHelper: { readFileSync, writeFile }, formatError, } = require('../../utils');
13
- let { default: config } = require('../../config');
12
+ const { log, formatError, fileHelper: { readFileSync, writeFile }, } = require('../../utils');
13
+ const { trace } = require('../../utils/log');
14
+ const { default: config } = require('../../config');
14
15
  const { getDeveloperHubUrl, getAllStackSpecificApps } = require('../../utils/marketplace-app-helper');
15
16
  module.exports = class ImportMarketplaceApps {
16
17
  constructor(importConfig, stackAPIClient) {
@@ -306,6 +307,7 @@ module.exports = class ImportMarketplaceApps {
306
307
  updateParam = Object.assign(Object.assign({ manifest: app.manifest }, installation), { configuration, server_configuration });
307
308
  }
308
309
  else if (installation.message) {
310
+ trace(installation, 'error', true);
309
311
  log(this.config, formatError(installation.message), 'success');
310
312
  await this.confirmToCloseProcess(installation);
311
313
  }
@@ -329,6 +331,7 @@ module.exports = class ImportMarketplaceApps {
329
331
  .get(response.redirect_url)
330
332
  .then(async ({ response }) => {
331
333
  if (_.includes([501, 403], response.status)) {
334
+ trace(response, 'error', true); // NOTE Log complete stack and hide on UI
332
335
  log(this.config, `${appName} - ${response.statusText}, OAuth api call failed.!`, 'error');
333
336
  log(this.config, formatError(response), 'error');
334
337
  await this.confirmToCloseProcess({ message: response.data });
@@ -338,6 +341,7 @@ module.exports = class ImportMarketplaceApps {
338
341
  }
339
342
  })
340
343
  .catch((error) => {
344
+ trace(error, 'error', true);
341
345
  if (_.includes([501, 403], error.status)) {
342
346
  log(this.config, formatError(error), 'error');
343
347
  }
@@ -403,13 +407,17 @@ module.exports = class ImportMarketplaceApps {
403
407
  })
404
408
  .then(({ data }) => {
405
409
  if (data.message) {
410
+ trace(data, 'error', true);
406
411
  log(this.config, formatError(data.message), 'success');
407
412
  }
408
413
  else {
409
414
  log(this.config, `${app.manifest.name} app config updated successfully.!`, 'success');
410
415
  }
411
416
  })
412
- .catch((error) => log(this.config, formatError(error), 'error'));
417
+ .catch((error) => {
418
+ trace(data, 'error', true);
419
+ log(this.config, formatError(error), 'error');
420
+ });
413
421
  }
414
422
  validateAppName(name) {
415
423
  if (name.length < 3 || name.length > 20) {
@@ -112,6 +112,16 @@ export default interface DefaultConfig {
112
112
  fileName: string;
113
113
  requiredKeys: string[];
114
114
  };
115
+ taxonomies: {
116
+ dirName: string;
117
+ fileName: string;
118
+ dependencies?: Modules[];
119
+ };
120
+ terms: {
121
+ dirName: string;
122
+ fileName: string;
123
+ dependencies?: Modules[];
124
+ };
115
125
  };
116
126
  languagesCode: string[];
117
127
  apis: {
@@ -140,4 +150,5 @@ export default interface DefaultConfig {
140
150
  getEncryptionKeyMaxRetry: number;
141
151
  createBackupDir?: string;
142
152
  overwriteSupportedModules: string[];
153
+ onlyTSModules: string[];
143
154
  }
@@ -20,7 +20,7 @@ export interface User {
20
20
  email: string;
21
21
  authtoken: string;
22
22
  }
23
- export type Modules = 'stack' | 'assets' | 'locales' | 'environments' | 'extensions' | 'webhooks' | 'global-fields' | 'entries' | 'content-types' | 'custom-roles' | 'workflows' | 'labels' | 'marketplace-apps';
23
+ export type Modules = 'stack' | 'assets' | 'locales' | 'environments' | 'extensions' | 'webhooks' | 'global-fields' | 'entries' | 'content-types' | 'custom-roles' | 'workflows' | 'labels' | 'marketplace-apps' | 'taxonomies';
24
24
  export type ModuleClassParams = {
25
25
  stackAPIClient: ReturnType<ContentstackClient['stack']>;
26
26
  importConfig: ImportConfig;
@@ -60,5 +60,15 @@ export interface CustomRoleConfig {
60
60
  fileName: string;
61
61
  customRolesLocalesFileName: string;
62
62
  }
63
+ export interface TaxonomiesConfig {
64
+ dirName: string;
65
+ fileName: string;
66
+ dependencies?: Modules[];
67
+ }
68
+ export interface TermsConfig {
69
+ dirName: string;
70
+ fileName: string;
71
+ dependencies?: Modules[];
72
+ }
63
73
  export { default as DefaultConfig } from './default-config';
64
74
  export { default as ImportConfig } from './import-config';
@@ -1,2 +1,2 @@
1
1
  import { ImportConfig } from '../types';
2
- export default function setupBackupDir(importConfig: ImportConfig): Promise<string>;
2
+ export default function backupHandler(importConfig: ImportConfig): Promise<string>;
@@ -5,44 +5,45 @@ const path = tslib_1.__importStar(require("path"));
5
5
  const fs_extra_1 = require("fs-extra");
6
6
  const cli_utilities_1 = require("@contentstack/cli-utilities");
7
7
  const index_1 = require("./index");
8
- function setupBackupDir(importConfig) {
9
- return new Promise(async (resolve, reject) => {
10
- if (importConfig.hasOwnProperty('useBackedupDir')) {
11
- return resolve(importConfig.useBackedupDir);
12
- }
13
- const subDir = isSubDirectory(importConfig);
14
- let backupDirPath;
15
- if (subDir) {
16
- backupDirPath = path.resolve(importConfig.contentDir, '..', '_backup_' + Math.floor(Math.random() * 1000));
17
- if (importConfig.createBackupDir) {
18
- cli_utilities_1.cliux.print(`Warning!!! Provided backup directory path is a sub directory of the content directory, Cannot copy to a sub directory. Hence new backup directory created - ${backupDirPath}`, {
19
- color: 'yellow',
20
- });
21
- }
8
+ async function backupHandler(importConfig) {
9
+ if (importConfig.hasOwnProperty('useBackedupDir')) {
10
+ return importConfig.useBackedupDir;
11
+ }
12
+ let backupDirPath;
13
+ const subDir = isSubDirectory(importConfig);
14
+ if (subDir) {
15
+ backupDirPath = path.resolve(importConfig.contentDir, '..', '_backup_' + Math.floor(Math.random() * 1000));
16
+ if (importConfig.createBackupDir) {
17
+ cli_utilities_1.cliux.print(`Warning!!! Provided backup directory path is a sub directory of the content directory, Cannot copy to a sub directory. Hence new backup directory created - ${backupDirPath}`, {
18
+ color: 'yellow',
19
+ });
22
20
  }
23
- else {
24
- //NOTE: If the backup folder's directory is provided, create it at that location; otherwise, the default path (working directory).
25
- backupDirPath = path.join(process.cwd(), '_backup_' + Math.floor(Math.random() * 1000));
26
- if (importConfig.createBackupDir) {
27
- if (index_1.fileHelper.fileExistsSync(importConfig.createBackupDir)) {
28
- index_1.fileHelper.removeDirSync(importConfig.createBackupDir);
29
- }
30
- index_1.fileHelper.makeDirectory(importConfig.createBackupDir);
31
- backupDirPath = importConfig.createBackupDir;
21
+ }
22
+ else {
23
+ // NOTE: If the backup folder's directory is provided, create it at that location; otherwise, the default path (working directory).
24
+ backupDirPath = path.join(process.cwd(), '_backup_' + Math.floor(Math.random() * 1000));
25
+ if (importConfig.createBackupDir) {
26
+ if (index_1.fileHelper.fileExistsSync(importConfig.createBackupDir)) {
27
+ index_1.fileHelper.removeDirSync(importConfig.createBackupDir);
32
28
  }
29
+ index_1.fileHelper.makeDirectory(importConfig.createBackupDir);
30
+ backupDirPath = importConfig.createBackupDir;
33
31
  }
34
- if (backupDirPath) {
35
- cli_utilities_1.cliux.print('Copying content to the backup directory...');
32
+ }
33
+ if (backupDirPath) {
34
+ cli_utilities_1.cliux.print('Copying content to the backup directory...');
35
+ return new Promise((resolve, reject) => {
36
36
  return (0, fs_extra_1.copy)(importConfig.contentDir, backupDirPath, (error) => {
37
37
  if (error) {
38
+ (0, index_1.trace)(error, 'error', true);
38
39
  return reject(error);
39
40
  }
40
- return resolve(backupDirPath);
41
+ resolve(backupDirPath);
41
42
  });
42
- }
43
- });
43
+ });
44
+ }
44
45
  }
45
- exports.default = setupBackupDir;
46
+ exports.default = backupHandler;
46
47
  /**
47
48
  * Check whether provided backup directory path is sub directory or not
48
49
  * @param importConfig
@@ -53,8 +54,8 @@ function isSubDirectory(importConfig) {
53
54
  const child = importConfig.createBackupDir ? importConfig.createBackupDir : process.cwd();
54
55
  const relative = path.relative(parent, child);
55
56
  if (relative) {
56
- return relative && !relative.startsWith('..') && !path.isAbsolute(relative);
57
+ return !relative.startsWith('..') && !path.isAbsolute(relative);
57
58
  }
58
- //true if both parent and child have same path
59
+ // true if both parent and child have same path
59
60
  return true;
60
61
  }
@@ -10,3 +10,5 @@ export { schemaTemplate, suppressSchemaReference, removeReferenceFields } from '
10
10
  export { lookupExtension } from './extension-helper';
11
11
  export { lookupEntries, removeUidsFromJsonRteFields, removeEntryRefsFromJSONRTE, restoreJsonRteEntryRefs, } from './entries-helper';
12
12
  export * from './common-helper';
13
+ export * from './log';
14
+ export { lookUpTaxonomy, lookUpTerms } from './taxonomies-helper';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.restoreJsonRteEntryRefs = exports.removeEntryRefsFromJSONRTE = exports.removeUidsFromJsonRteFields = exports.lookupEntries = exports.lookupExtension = exports.removeReferenceFields = exports.suppressSchemaReference = exports.schemaTemplate = exports.updateAppConfig = exports.ifAppAlreadyExist = exports.getAllStackSpecificApps = exports.confirmToCloseProcess = exports.makeRedirectUrlCall = exports.installApp = exports.handleNameConflict = exports.createPrivateApp = exports.getConfirmationToCreateApps = exports.getOrgUid = exports.getDeveloperHubUrl = exports.lookupAssets = exports.uploadAssetHelper = exports.unlinkFileLogger = exports.log = exports.backupHandler = exports.fsUtil = exports.fileHelper = exports.setupImportConfig = exports.interactive = void 0;
3
+ exports.lookUpTerms = exports.lookUpTaxonomy = exports.restoreJsonRteEntryRefs = exports.removeEntryRefsFromJSONRTE = exports.removeUidsFromJsonRteFields = exports.lookupEntries = exports.lookupExtension = exports.removeReferenceFields = exports.suppressSchemaReference = exports.schemaTemplate = exports.updateAppConfig = exports.ifAppAlreadyExist = exports.getAllStackSpecificApps = exports.confirmToCloseProcess = exports.makeRedirectUrlCall = exports.installApp = exports.handleNameConflict = exports.createPrivateApp = exports.getConfirmationToCreateApps = exports.getOrgUid = exports.getDeveloperHubUrl = exports.lookupAssets = exports.uploadAssetHelper = exports.unlinkFileLogger = exports.log = exports.backupHandler = exports.fsUtil = exports.fileHelper = exports.setupImportConfig = exports.interactive = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  exports.interactive = tslib_1.__importStar(require("./interactive"));
6
6
  var import_config_handler_1 = require("./import-config-handler");
@@ -40,3 +40,7 @@ Object.defineProperty(exports, "removeUidsFromJsonRteFields", { enumerable: true
40
40
  Object.defineProperty(exports, "removeEntryRefsFromJSONRTE", { enumerable: true, get: function () { return entries_helper_1.removeEntryRefsFromJSONRTE; } });
41
41
  Object.defineProperty(exports, "restoreJsonRteEntryRefs", { enumerable: true, get: function () { return entries_helper_1.restoreJsonRteEntryRefs; } });
42
42
  tslib_1.__exportStar(require("./common-helper"), exports);
43
+ tslib_1.__exportStar(require("./log"), exports);
44
+ var taxonomies_helper_1 = require("./taxonomies-helper");
45
+ Object.defineProperty(exports, "lookUpTaxonomy", { enumerable: true, get: function () { return taxonomies_helper_1.lookUpTaxonomy; } });
46
+ Object.defineProperty(exports, "lookUpTerms", { enumerable: true, get: function () { return taxonomies_helper_1.lookUpTerms; } });
@@ -0,0 +1,10 @@
1
+ import { LogEntry } from 'winston/index';
2
+ import { Logger } from '@contentstack/cli-utilities';
3
+ import { LogsType, MessageType } from '@contentstack/cli-utilities/lib/logger';
4
+ import { ImportConfig } from '../types';
5
+ export declare function isImportConfig(config: ImportConfig | MessageType): config is ImportConfig;
6
+ export declare function log(entry: LogEntry): void;
7
+ export declare function log(error: MessageType, logType: LogsType): void;
8
+ export declare function log(error: MessageType, logType: 'error', hidden: boolean): void;
9
+ export declare function initLogger(config?: ImportConfig | undefined): Logger;
10
+ export declare const trace: typeof log;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.trace = exports.initLogger = exports.log = exports.isImportConfig = void 0;
4
+ const path_1 = require("path");
5
+ const cli_utilities_1 = require("@contentstack/cli-utilities");
6
+ let logger;
7
+ function isImportConfig(config) {
8
+ return config.data !== undefined && (config === null || config === void 0 ? void 0 : config.contentVersion) !== undefined;
9
+ }
10
+ exports.isImportConfig = isImportConfig;
11
+ function log(entryOrMessage, logType, hidden) {
12
+ logger = initLogger();
13
+ if (logType === 'error') {
14
+ logger.log(entryOrMessage, logType, hidden);
15
+ }
16
+ else {
17
+ logger.log(entryOrMessage, logType);
18
+ }
19
+ }
20
+ exports.log = log;
21
+ function initLogger(config) {
22
+ var _a;
23
+ if (!logger) {
24
+ const basePath = (0, path_1.join)((_a = config === null || config === void 0 ? void 0 : config.data) !== null && _a !== void 0 ? _a : process.cwd(), 'logs', 'import');
25
+ logger = new cli_utilities_1.Logger(Object.assign(config !== null && config !== void 0 ? config : {}, { basePath }));
26
+ }
27
+ return logger;
28
+ }
29
+ exports.initLogger = initLogger;
30
+ exports.trace = log;
@@ -9,7 +9,6 @@ exports.unlinkFileLogger = exports.log = void 0;
9
9
  const tslib_1 = require("tslib");
10
10
  const winston = tslib_1.__importStar(require("winston"));
11
11
  const path = tslib_1.__importStar(require("path"));
12
- const mkdirp_1 = tslib_1.__importDefault(require("mkdirp"));
13
12
  const slice = Array.prototype.slice;
14
13
  const ansiRegexPattern = [
15
14
  '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
@@ -55,9 +54,7 @@ let successTransport;
55
54
  let errorTransport;
56
55
  function init(_logPath) {
57
56
  if (!logger || !errorLogger) {
58
- var logsDir = path.resolve(_logPath, 'logs', 'import');
59
- // Create dir if doesn't already exist
60
- mkdirp_1.default.sync(logsDir);
57
+ const logsDir = path.resolve(_logPath, 'logs', 'import');
61
58
  successTransport = {
62
59
  filename: path.join(logsDir, 'success.log'),
63
60
  maxFiles: 20,
@@ -75,7 +72,9 @@ function init(_logPath) {
75
72
  logger = winston.createLogger({
76
73
  transports: [
77
74
  new winston.transports.File(successTransport),
78
- new winston.transports.Console({ format: winston.format.simple() }),
75
+ new winston.transports.Console({
76
+ format: winston.format.combine(winston.format.simple(), winston.format.colorize({ all: true, colors: { warn: 'yellow', info: 'white' } })),
77
+ }),
79
78
  ],
80
79
  levels: myCustomLevels.levels,
81
80
  });
@@ -98,7 +97,7 @@ function init(_logPath) {
98
97
  logger.log('info', logString);
99
98
  }
100
99
  },
101
- warn: function () {
100
+ warn: function (message) {
102
101
  let args = slice.call(arguments);
103
102
  let logString = returnString(args);
104
103
  if (logString) {
@@ -126,7 +125,10 @@ const log = async (config, message, type) => {
126
125
  // ignoring the type argument, as we are not using it to create a logfile anymore
127
126
  if (type !== 'error') {
128
127
  // removed type argument from init method
129
- init(config.data).log(message);
128
+ if (type === 'warn')
129
+ init(config.data).warn(message); //logged warning message in log file
130
+ else
131
+ init(config.data).log(message);
130
132
  }
131
133
  else {
132
134
  init(config.data).error(message);
@@ -9,12 +9,13 @@ const includes_1 = tslib_1.__importDefault(require("lodash/includes"));
9
9
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
10
10
  const cli_utilities_1 = require("@contentstack/cli-utilities");
11
11
  const logger_1 = require("./logger");
12
- const interactive_1 = require("./interactive");
12
+ const log_1 = require("../utils/log");
13
13
  const utils_1 = require("../utils");
14
+ const interactive_1 = require("./interactive");
14
15
  const interactive_2 = require("../utils/interactive");
15
16
  const getAllStackSpecificApps = async (developerHubBaseUrl, httpClient, config) => {
16
17
  const appSdkAxiosInstance = await (0, cli_utilities_1.managementSDKClient)({
17
- host: developerHubBaseUrl.split('://').pop()
18
+ host: developerHubBaseUrl.split('://').pop(),
18
19
  });
19
20
  return await appSdkAxiosInstance.axiosInstance
20
21
  .get(`${developerHubBaseUrl}/installations?target_uids=${config.target_stack}`, {
@@ -23,7 +24,10 @@ const getAllStackSpecificApps = async (developerHubBaseUrl, httpClient, config)
23
24
  },
24
25
  })
25
26
  .then(({ data }) => data.data)
26
- .catch((error) => (0, logger_1.log)(config, `Failed to export marketplace-apps ${(0, utils_1.formatError)(error)}`, 'error'));
27
+ .catch((error) => {
28
+ (0, log_1.trace)(error, 'error', true);
29
+ (0, logger_1.log)(config, `Failed to export marketplace-apps ${(0, utils_1.formatError)(error)}`, 'error');
30
+ });
27
31
  };
28
32
  exports.getAllStackSpecificApps = getAllStackSpecificApps;
29
33
  const getDeveloperHubUrl = async (config) => {
@@ -41,6 +45,7 @@ const getOrgUid = async (config) => {
41
45
  .stack({ api_key: config.target_stack })
42
46
  .fetch()
43
47
  .catch((error) => {
48
+ (0, log_1.trace)(error, 'error', true);
44
49
  (0, logger_1.log)(config, (0, utils_1.formatError)(error), 'error');
45
50
  });
46
51
  return (tempStackData === null || tempStackData === void 0 ? void 0 : tempStackData.org_uid) || '';
@@ -92,6 +97,7 @@ const makeRedirectUrlCall = async (response, appName, config) => {
92
97
  .get(response.redirect_url)
93
98
  .then(async ({ response }) => {
94
99
  if ((0, includes_1.default)([501, 403], response.status)) {
100
+ (0, log_1.trace)(response, 'error', true);
95
101
  (0, logger_1.log)(config, `${appName} - ${response.statusText}, OAuth api call failed.!`, 'error');
96
102
  (0, logger_1.log)(config, (0, utils_1.formatError)(response), 'error');
97
103
  await (0, exports.confirmToCloseProcess)(response.data, config);
@@ -101,6 +107,7 @@ const makeRedirectUrlCall = async (response, appName, config) => {
101
107
  }
102
108
  })
103
109
  .catch((error) => {
110
+ (0, log_1.trace)(error, 'error', true);
104
111
  if ((0, includes_1.default)([501, 403], error.status)) {
105
112
  (0, logger_1.log)(config, (0, utils_1.formatError)(error), 'error');
106
113
  }
@@ -145,6 +152,9 @@ const updateAppConfig = async (client, config, app, payload) => {
145
152
  var _a;
146
153
  (0, logger_1.log)(config, `${(_a = app === null || app === void 0 ? void 0 : app.manifest) === null || _a === void 0 ? void 0 : _a.name} app config updated successfully.!`, 'success');
147
154
  })
148
- .catch((error) => (0, logger_1.log)(config, `Failed to update app config.${(0, utils_1.formatError)(error)}`, 'error'));
155
+ .catch((error) => {
156
+ (0, log_1.trace)(error, 'error', true);
157
+ (0, logger_1.log)(config, `Failed to update app config.${(0, utils_1.formatError)(error)}`, 'error');
158
+ });
149
159
  };
150
160
  exports.updateAppConfig = updateAppConfig;
@@ -0,0 +1,16 @@
1
+ import { ImportConfig } from '../types';
2
+ /**
3
+ * check and remove if referenced taxonomy doesn't exists in stack
4
+ * @param {any} schema content type schema
5
+ * @param {Record<string, unknown>} taxonomies created taxonomies
6
+ * @param {ImportConfig} importConfig
7
+ */
8
+ export declare const lookUpTaxonomy: (importConfig: ImportConfig, schema: any, taxonomies: Record<string, unknown>) => void;
9
+ /**
10
+ * check and remove if referenced terms doesn't exists in taxonomy
11
+ * @param {Record<string, any>[]} ctSchema content type schema
12
+ * @param {any} entry
13
+ * @param {Record<string, any>} taxonomiesAndTermData created taxonomies and terms
14
+ * @param {ImportConfig} importConfig
15
+ */
16
+ export declare const lookUpTerms: (ctSchema: Record<string, any>[], entry: any, taxonomiesAndTermData: Record<string, any>, importConfig: ImportConfig) => void;
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.lookUpTerms = exports.lookUpTaxonomy = void 0;
4
+ /**
5
+ * taxonomy lookup
6
+ */
7
+ const _1 = require("./");
8
+ /**
9
+ * check and remove if referenced taxonomy doesn't exists in stack
10
+ * @param {any} schema content type schema
11
+ * @param {Record<string, unknown>} taxonomies created taxonomies
12
+ * @param {ImportConfig} importConfig
13
+ */
14
+ const lookUpTaxonomy = function (importConfig, schema, taxonomies) {
15
+ for (let i in schema) {
16
+ if (schema[i].data_type === 'taxonomy') {
17
+ const taxonomyFieldData = schema[i].taxonomies;
18
+ const { updatedTaxonomyData, isTaxonomyFieldRemoved } = verifyAndRemoveTaxonomy(taxonomyFieldData, taxonomies, importConfig);
19
+ //Handle API error -> The 'taxonomies' property must have atleast one taxonomy object. Remove taxonomy field from schema.
20
+ if (isTaxonomyFieldRemoved) {
21
+ schema.splice(i, 1);
22
+ }
23
+ else {
24
+ schema[i].taxonomies = updatedTaxonomyData;
25
+ }
26
+ }
27
+ }
28
+ };
29
+ exports.lookUpTaxonomy = lookUpTaxonomy;
30
+ /**
31
+ * verify and remove referenced taxonomy with warning from respective content type
32
+ * @param {Record<string, any>[]} taxonomyFieldData
33
+ * @param {Record<string, unknown>} taxonomies created taxonomies
34
+ * @param {ImportConfig} importConfig
35
+ * @returns
36
+ */
37
+ const verifyAndRemoveTaxonomy = function (taxonomyFieldData, taxonomies, importConfig) {
38
+ let isTaxonomyFieldRemoved = false;
39
+ for (let index = 0; index < (taxonomyFieldData === null || taxonomyFieldData === void 0 ? void 0 : taxonomyFieldData.length); index++) {
40
+ const taxonomyData = taxonomyFieldData[index];
41
+ if (taxonomies === undefined || !taxonomies.hasOwnProperty(taxonomyData === null || taxonomyData === void 0 ? void 0 : taxonomyData.taxonomy_uid)) {
42
+ // remove taxonomy from taxonomies field data with warning if respective taxonomy doesn't exists
43
+ (0, _1.log)(importConfig, `Taxonomy '${taxonomyData === null || taxonomyData === void 0 ? void 0 : taxonomyData.taxonomy_uid}' does not exist. Removing the data from the taxonomies field`, 'warn');
44
+ taxonomyFieldData.splice(index, 1);
45
+ --index;
46
+ }
47
+ }
48
+ if (!(taxonomyFieldData === null || taxonomyFieldData === void 0 ? void 0 : taxonomyFieldData.length)) {
49
+ (0, _1.log)(importConfig, 'Taxonomy does not exist. Removing the field from content type', 'warn');
50
+ isTaxonomyFieldRemoved = true;
51
+ }
52
+ return {
53
+ updatedTaxonomyData: taxonomyFieldData,
54
+ isTaxonomyFieldRemoved,
55
+ };
56
+ };
57
+ /**
58
+ * check and remove if referenced terms doesn't exists in taxonomy
59
+ * @param {Record<string, any>[]} ctSchema content type schema
60
+ * @param {any} entry
61
+ * @param {Record<string, any>} taxonomiesAndTermData created taxonomies and terms
62
+ * @param {ImportConfig} importConfig
63
+ */
64
+ const lookUpTerms = function (ctSchema, entry, taxonomiesAndTermData, importConfig) {
65
+ for (let index = 0; index < (ctSchema === null || ctSchema === void 0 ? void 0 : ctSchema.length); index++) {
66
+ if (ctSchema[index].data_type === 'taxonomy') {
67
+ const taxonomyFieldData = entry[ctSchema[index].uid];
68
+ const updatedTaxonomyData = verifyAndRemoveTerms(taxonomyFieldData, taxonomiesAndTermData, importConfig);
69
+ entry[ctSchema[index].uid] = updatedTaxonomyData;
70
+ }
71
+ }
72
+ };
73
+ exports.lookUpTerms = lookUpTerms;
74
+ /**
75
+ * verify and remove referenced term with warning from respective entry
76
+ * @param {Record<string, any>[]} taxonomyFieldData entry taxonomies data
77
+ * @param {Record<string, any>} taxonomiesAndTermData created taxonomies and terms
78
+ * @param {ImportConfig} importConfig
79
+ * @returns { Record<string, any>[]}
80
+ */
81
+ const verifyAndRemoveTerms = function (taxonomyFieldData, taxonomiesAndTermData, importConfig) {
82
+ for (let index = 0; index < (taxonomyFieldData === null || taxonomyFieldData === void 0 ? void 0 : taxonomyFieldData.length); index++) {
83
+ const taxonomyData = taxonomyFieldData[index];
84
+ const taxUID = taxonomyData === null || taxonomyData === void 0 ? void 0 : taxonomyData.taxonomy_uid;
85
+ const termUID = taxonomyData === null || taxonomyData === void 0 ? void 0 : taxonomyData.term_uid;
86
+ if (taxonomiesAndTermData === undefined ||
87
+ !taxonomiesAndTermData.hasOwnProperty(taxUID) ||
88
+ (taxonomiesAndTermData.hasOwnProperty(taxUID) && !taxonomiesAndTermData[taxUID].hasOwnProperty(termUID))) {
89
+ // remove term from taxonomies field data with warning if respective term doesn't exists
90
+ (0, _1.log)(importConfig, `Term '${termUID}' does not exist. Removing it from taxonomy - '${taxUID}'`, 'warn');
91
+ taxonomyFieldData.splice(index, 1);
92
+ --index;
93
+ }
94
+ }
95
+ return taxonomyFieldData;
96
+ };
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.10.0",
2
+ "version": "1.11.0",
3
3
  "commands": {
4
4
  "cm:stacks:import": {
5
5
  "id": "cm:stacks:import",
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "@contentstack/cli-cm-import",
3
3
  "description": "Contentstack CLI plugin to import content into stack",
4
- "version": "1.10.0",
4
+ "version": "1.11.0",
5
5
  "author": "Contentstack",
6
6
  "bugs": "https://github.com/contentstack/cli/issues",
7
7
  "dependencies": {
8
- "@contentstack/cli-command": "~1.2.14",
9
- "@contentstack/cli-utilities": "~1.5.4",
10
- "@contentstack/management": "~1.10.2",
8
+ "@contentstack/cli-command": "~1.2.15",
9
+ "@contentstack/cli-utilities": "~1.5.5",
10
+ "@contentstack/management": "~1.12.0",
11
11
  "@oclif/core": "^2.9.3",
12
+ "axios": "^1.6.0",
12
13
  "big-json": "^3.2.0",
13
14
  "bluebird": "^3.7.2",
14
15
  "chalk": "^4.1.2",
@@ -96,4 +97,4 @@
96
97
  }
97
98
  },
98
99
  "repository": "https://github.com/contentstack/cli"
99
- }
100
+ }