@contentstack/cli-cm-import-setup 1.0.0-beta.1
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/LICENSE +21 -0
- package/README.md +115 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +6 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +7 -0
- package/lib/commands/cm/stacks/import-setup.d.ts +10 -0
- package/lib/commands/cm/stacks/import-setup.js +53 -0
- package/lib/config/index.d.ts +3 -0
- package/lib/config/index.js +77 -0
- package/lib/import/import-setup.d.ts +32 -0
- package/lib/import/import-setup.js +112 -0
- package/lib/import/index.d.ts +1 -0
- package/lib/import/index.js +8 -0
- package/lib/import/modules/assets.d.ts +27 -0
- package/lib/import/modules/assets.js +102 -0
- package/lib/import/modules/base-setup.d.ts +37 -0
- package/lib/import/modules/base-setup.js +183 -0
- package/lib/import/modules/content-types.d.ts +6 -0
- package/lib/import/modules/content-types.js +20 -0
- package/lib/import/modules/custom-roles.d.ts +0 -0
- package/lib/import/modules/custom-roles.js +0 -0
- package/lib/import/modules/entries.d.ts +6 -0
- package/lib/import/modules/entries.js +20 -0
- package/lib/import/modules/extensions.d.ts +20 -0
- package/lib/import/modules/extensions.js +61 -0
- package/lib/import/modules/global-fields.d.ts +0 -0
- package/lib/import/modules/global-fields.js +0 -0
- package/lib/import/modules/index.d.ts +0 -0
- package/lib/import/modules/index.js +0 -0
- package/lib/import/modules/marketplace-apps.d.ts +26 -0
- package/lib/import/modules/marketplace-apps.js +81 -0
- package/lib/import/modules/taxonomies.d.ts +53 -0
- package/lib/import/modules/taxonomies.js +141 -0
- package/lib/types/default-config.d.ts +55 -0
- package/lib/types/default-config.js +2 -0
- package/lib/types/import-config.d.ts +55 -0
- package/lib/types/import-config.js +2 -0
- package/lib/types/index.d.ts +115 -0
- package/lib/types/index.js +2 -0
- package/lib/utils/backup-handler.d.ts +2 -0
- package/lib/utils/backup-handler.js +61 -0
- package/lib/utils/common-helper.d.ts +0 -0
- package/lib/utils/common-helper.js +0 -0
- package/lib/utils/file-helper.d.ts +15 -0
- package/lib/utils/file-helper.js +144 -0
- package/lib/utils/import-config-handler.d.ts +3 -0
- package/lib/utils/import-config-handler.js +91 -0
- package/lib/utils/index.d.ts +7 -0
- package/lib/utils/index.js +16 -0
- package/lib/utils/interactive.d.ts +3 -0
- package/lib/utils/interactive.js +38 -0
- package/lib/utils/log.d.ts +12 -0
- package/lib/utils/log.js +31 -0
- package/lib/utils/logger.d.ts +8 -0
- package/lib/utils/logger.js +157 -0
- package/lib/utils/login-handler.d.ts +8 -0
- package/lib/utils/login-handler.js +53 -0
- package/messages/index.json +1 -0
- package/oclif.manifest.json +56 -0
- package/package.json +96 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
const utils_1 = require("../../utils");
|
|
27
|
+
const lodash_1 = require("lodash");
|
|
28
|
+
class BaseImportSetup {
|
|
29
|
+
constructor({ config, stackAPIClient, dependencies }) {
|
|
30
|
+
this.config = config;
|
|
31
|
+
this.stackAPIClient = stackAPIClient;
|
|
32
|
+
this.dependencies = dependencies;
|
|
33
|
+
}
|
|
34
|
+
async setupDependencies() {
|
|
35
|
+
var _a;
|
|
36
|
+
for (const moduleName of this.dependencies) {
|
|
37
|
+
try {
|
|
38
|
+
const modulePath = `./${moduleName}`;
|
|
39
|
+
const { default: ModuleClass } = await (_a = modulePath, Promise.resolve().then(() => __importStar(require(_a))));
|
|
40
|
+
const modulePayload = {
|
|
41
|
+
config: this.config,
|
|
42
|
+
stackAPIClient: this.stackAPIClient,
|
|
43
|
+
};
|
|
44
|
+
const moduleInstance = new ModuleClass(modulePayload);
|
|
45
|
+
await moduleInstance.start();
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
(0, utils_1.log)(this.config, `Error importing '${moduleName}': ${error.message}`, 'error');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* @method delay
|
|
54
|
+
* @param {number} ms number
|
|
55
|
+
* @returns {Promise} Promise<void>
|
|
56
|
+
*/
|
|
57
|
+
delay(ms) {
|
|
58
|
+
/* eslint-disable no-promise-executor-return */
|
|
59
|
+
return new Promise((resolve) => setTimeout(resolve, ms <= 0 ? 0 : ms));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* @method makeConcurrentCall
|
|
63
|
+
* @param {Record<string, any>} env EnvType
|
|
64
|
+
* @param {CustomPromiseHandler} promisifyHandler CustomPromiseHandler
|
|
65
|
+
* @param {boolean} logBatchCompletionMsg boolean
|
|
66
|
+
* @returns {Promise} Promise<void>
|
|
67
|
+
*/
|
|
68
|
+
makeConcurrentCall(env, promisifyHandler, logBatchCompletionMsg = true) {
|
|
69
|
+
const { apiParams, apiContent, processName, indexerCount, currentIndexer, concurrencyLimit = this.config.fetchConcurrency, } = env;
|
|
70
|
+
/* eslint-disable no-async-promise-executor */
|
|
71
|
+
return new Promise(async (resolve) => {
|
|
72
|
+
let batchNo = 0;
|
|
73
|
+
let isLastRequest = false;
|
|
74
|
+
const batches = (0, lodash_1.chunk)(apiContent, concurrencyLimit);
|
|
75
|
+
/* eslint-disable no-promise-executor-return */
|
|
76
|
+
if ((0, lodash_1.isEmpty)(batches))
|
|
77
|
+
return resolve();
|
|
78
|
+
for (const [batchIndex, batch] of (0, lodash_1.entries)(batches)) {
|
|
79
|
+
batchNo += 1;
|
|
80
|
+
const allPromise = [];
|
|
81
|
+
const start = Date.now();
|
|
82
|
+
for (const [index, element] of (0, lodash_1.entries)(batch)) {
|
|
83
|
+
let promise = Promise.resolve();
|
|
84
|
+
isLastRequest = (0, lodash_1.isEqual)((0, lodash_1.last)(batch), element) && (0, lodash_1.isEqual)((0, lodash_1.last)(batches), batch);
|
|
85
|
+
if (promisifyHandler instanceof Function) {
|
|
86
|
+
promise = promisifyHandler({
|
|
87
|
+
apiParams,
|
|
88
|
+
isLastRequest,
|
|
89
|
+
element,
|
|
90
|
+
index: Number(index),
|
|
91
|
+
batchIndex: Number(batchIndex),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
else if (apiParams) {
|
|
95
|
+
apiParams.apiData = element;
|
|
96
|
+
promise = this.makeAPICall(apiParams, isLastRequest);
|
|
97
|
+
}
|
|
98
|
+
allPromise.push(promise);
|
|
99
|
+
}
|
|
100
|
+
/* eslint-disable no-await-in-loop */
|
|
101
|
+
await Promise.allSettled(allPromise);
|
|
102
|
+
/* eslint-disable no-await-in-loop */
|
|
103
|
+
await this.logMsgAndWaitIfRequired(processName, start, batches.length, batchNo, logBatchCompletionMsg, indexerCount, currentIndexer);
|
|
104
|
+
if (isLastRequest)
|
|
105
|
+
resolve();
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* @method logMsgAndWaitIfRequired
|
|
111
|
+
* @param {string} processName string
|
|
112
|
+
* @param {number} start number
|
|
113
|
+
* @param {number} batchNo - number
|
|
114
|
+
* @returns {Promise} Promise<void>
|
|
115
|
+
*/
|
|
116
|
+
async logMsgAndWaitIfRequired(processName, start, totelBatches, batchNo, logBatchCompletionMsg = true, indexerCount, currentIndexer) {
|
|
117
|
+
const end = Date.now();
|
|
118
|
+
const exeTime = end - start;
|
|
119
|
+
if (logBatchCompletionMsg) {
|
|
120
|
+
let batchMsg = '';
|
|
121
|
+
// info: Batch No. 20 of import assets is complete
|
|
122
|
+
if (currentIndexer)
|
|
123
|
+
batchMsg += `Current chunk processing is (${currentIndexer}/${indexerCount})`;
|
|
124
|
+
(0, utils_1.log)(this.config, `Batch No. (${batchNo}/${totelBatches}) of ${processName} is complete`, 'success');
|
|
125
|
+
}
|
|
126
|
+
// if (this.config.modules.assets.displayExecutionTime) {
|
|
127
|
+
// console.log(
|
|
128
|
+
// `Time taken to execute: ${exeTime} milliseconds; wait time: ${
|
|
129
|
+
// exeTime < 1000 ? 1000 - exeTime : 0
|
|
130
|
+
// } milliseconds`,
|
|
131
|
+
// );
|
|
132
|
+
// }
|
|
133
|
+
if (exeTime < 1000)
|
|
134
|
+
await this.delay(1000 - exeTime);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* @method makeAPICall
|
|
138
|
+
* @param {Record<string, any>} apiOptions - Api related params
|
|
139
|
+
* @param {Record<string, any>} isLastRequest - Boolean
|
|
140
|
+
* @return {Promise} Promise<void>
|
|
141
|
+
*/
|
|
142
|
+
makeAPICall(apiOptions, isLastRequest = false) {
|
|
143
|
+
if (apiOptions.serializeData instanceof Function) {
|
|
144
|
+
apiOptions = apiOptions.serializeData(apiOptions);
|
|
145
|
+
}
|
|
146
|
+
const { uid, entity, reject, resolve, apiData, additionalInfo = {}, includeParamOnCompletion } = apiOptions;
|
|
147
|
+
const onSuccess = (response) => resolve({
|
|
148
|
+
response,
|
|
149
|
+
isLastRequest,
|
|
150
|
+
additionalInfo,
|
|
151
|
+
apiData: includeParamOnCompletion ? apiData : undefined,
|
|
152
|
+
});
|
|
153
|
+
const onReject = (error) => reject({
|
|
154
|
+
error,
|
|
155
|
+
isLastRequest,
|
|
156
|
+
additionalInfo,
|
|
157
|
+
apiData: includeParamOnCompletion ? apiData : undefined,
|
|
158
|
+
});
|
|
159
|
+
if (!apiData) {
|
|
160
|
+
return Promise.resolve();
|
|
161
|
+
}
|
|
162
|
+
switch (entity) {
|
|
163
|
+
case 'fetch-assets':
|
|
164
|
+
return this.stackAPIClient
|
|
165
|
+
.asset()
|
|
166
|
+
.query({
|
|
167
|
+
query: {
|
|
168
|
+
$and: [
|
|
169
|
+
{ file_size: Number(apiData.file_size) },
|
|
170
|
+
{ filename: apiData.filename },
|
|
171
|
+
{ title: apiData.title },
|
|
172
|
+
],
|
|
173
|
+
},
|
|
174
|
+
})
|
|
175
|
+
.find()
|
|
176
|
+
.then(onSuccess)
|
|
177
|
+
.catch(onReject);
|
|
178
|
+
default:
|
|
179
|
+
return Promise.resolve();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
exports.default = BaseImportSetup;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const utils_1 = require("../../utils");
|
|
5
|
+
const base_setup_1 = tslib_1.__importDefault(require("./base-setup"));
|
|
6
|
+
class ContentTypesImportSetup extends base_setup_1.default {
|
|
7
|
+
constructor(options) {
|
|
8
|
+
super(options);
|
|
9
|
+
}
|
|
10
|
+
async start() {
|
|
11
|
+
try {
|
|
12
|
+
await this.setupDependencies();
|
|
13
|
+
(0, utils_1.log)(this.config, `Generate required setup files for content types`, 'success');
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
(0, utils_1.log)(this.config, `Error generating ${error.message}`, 'error');
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.default = ContentTypesImportSetup;
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const utils_1 = require("../../utils");
|
|
5
|
+
const base_setup_1 = tslib_1.__importDefault(require("./base-setup"));
|
|
6
|
+
class EntriesImportSetup extends base_setup_1.default {
|
|
7
|
+
constructor(options) {
|
|
8
|
+
super(options);
|
|
9
|
+
}
|
|
10
|
+
async start() {
|
|
11
|
+
try {
|
|
12
|
+
await this.setupDependencies();
|
|
13
|
+
(0, utils_1.log)(this.config, `Generate required setup files for entries`, 'success');
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
(0, utils_1.log)(this.config, `Error generating ${error.message}`, 'error');
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.default = EntriesImportSetup;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ModuleClassParams } from '../../types';
|
|
2
|
+
export default class ExtensionImportSetup {
|
|
3
|
+
private config;
|
|
4
|
+
private extensionsFilePath;
|
|
5
|
+
private extensionMapper;
|
|
6
|
+
private stackAPIClient;
|
|
7
|
+
private dependencies;
|
|
8
|
+
private extensionsConfig;
|
|
9
|
+
private mapperDirPath;
|
|
10
|
+
private extensionsFolderPath;
|
|
11
|
+
private extUidMapperPath;
|
|
12
|
+
constructor({ config, stackAPIClient }: ModuleClassParams);
|
|
13
|
+
/**
|
|
14
|
+
* Start the extension import setup
|
|
15
|
+
* This method reads the extensions from the content folder and generates a mapper file
|
|
16
|
+
* @returns {Promise<void>}
|
|
17
|
+
*/
|
|
18
|
+
start(): Promise<void>;
|
|
19
|
+
getExtension(extension: any): Promise<unknown>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const utils_1 = require("../../utils");
|
|
4
|
+
const path_1 = require("path");
|
|
5
|
+
const lodash_1 = require("lodash");
|
|
6
|
+
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
7
|
+
class ExtensionImportSetup {
|
|
8
|
+
constructor({ config, stackAPIClient }) {
|
|
9
|
+
this.config = config;
|
|
10
|
+
this.stackAPIClient = stackAPIClient;
|
|
11
|
+
this.extensionsFilePath = (0, path_1.join)((0, cli_utilities_1.sanitizePath)(this.config.contentDir), 'extensions', 'extensions.json');
|
|
12
|
+
this.extensionsConfig = config.modules.extensions;
|
|
13
|
+
this.extUidMapperPath = (0, path_1.join)((0, cli_utilities_1.sanitizePath)(this.config.backupDir), 'mapper', 'extensions', 'uid-mapping.json');
|
|
14
|
+
this.extensionMapper = {};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Start the extension import setup
|
|
18
|
+
* This method reads the extensions from the content folder and generates a mapper file
|
|
19
|
+
* @returns {Promise<void>}
|
|
20
|
+
*/
|
|
21
|
+
async start() {
|
|
22
|
+
try {
|
|
23
|
+
const extensions = await utils_1.fsUtil.readFile(this.extensionsFilePath);
|
|
24
|
+
if (!(0, lodash_1.isEmpty)(extensions)) {
|
|
25
|
+
// 2. Create mapper directory
|
|
26
|
+
const mapperFilePath = (0, path_1.join)((0, cli_utilities_1.sanitizePath)(this.config.backupDir), 'mapper', 'extensions');
|
|
27
|
+
utils_1.fsUtil.makeDirectory(mapperFilePath); // Use fsUtil
|
|
28
|
+
for (const extension of Object.values(extensions)) {
|
|
29
|
+
const targetExtension = await this.getExtension(extension);
|
|
30
|
+
if (!targetExtension) {
|
|
31
|
+
(0, utils_1.log)(this.config, `Extension with title '${extension.title}' not found in the stack!`, 'info');
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
this.extensionMapper[extension.uid] = targetExtension.uid;
|
|
35
|
+
}
|
|
36
|
+
await utils_1.fsUtil.writeFile(this.extUidMapperPath, this.extensionMapper);
|
|
37
|
+
(0, utils_1.log)(this.config, `Generated required setup files for extension`, 'success');
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
(0, utils_1.log)(this.config, 'No extensions found in the content folder!', 'error');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
(0, utils_1.log)(this.config, `Error generating extension mapper: ${(0, cli_utilities_1.formatError)(error)}`, 'error');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async getExtension(extension) {
|
|
48
|
+
// Implement this method to get the extension from the stack
|
|
49
|
+
return new Promise(async (resolve, reject) => {
|
|
50
|
+
const { items: [extensionsInStack] = [] } = (await this.stackAPIClient
|
|
51
|
+
.extension()
|
|
52
|
+
.query({ query: { title: extension.title } })
|
|
53
|
+
.findOne()
|
|
54
|
+
.catch((error) => {
|
|
55
|
+
reject(error);
|
|
56
|
+
})) || {};
|
|
57
|
+
resolve(extensionsInStack);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.default = ExtensionImportSetup;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ModuleClassParams } from '../../types';
|
|
2
|
+
import { ContentstackMarketplaceClient, NodeCrypto } from '@contentstack/cli-utilities';
|
|
3
|
+
export default class marketplaceAppImportSetup {
|
|
4
|
+
private config;
|
|
5
|
+
private marketplaceAppsFilePath;
|
|
6
|
+
private marketplaceAppMapper;
|
|
7
|
+
private stackAPIClient;
|
|
8
|
+
private dependencies;
|
|
9
|
+
private marketplaceAppsConfig;
|
|
10
|
+
private mapperDirPath;
|
|
11
|
+
private marketplaceAppsFolderPath;
|
|
12
|
+
private marketplaceAppsUidMapperPath;
|
|
13
|
+
developerHubBaseUrl: string;
|
|
14
|
+
marketplaceAppPath: string;
|
|
15
|
+
nodeCrypto: NodeCrypto;
|
|
16
|
+
appSdk: ContentstackMarketplaceClient;
|
|
17
|
+
constructor({ config, stackAPIClient }: ModuleClassParams);
|
|
18
|
+
/**
|
|
19
|
+
* Start the marketplaceApp import setup
|
|
20
|
+
* This method reads the marketplaceApps from the content folder and generates a mapper file
|
|
21
|
+
* @returns {Promise<void>}
|
|
22
|
+
*/
|
|
23
|
+
start(): Promise<void>;
|
|
24
|
+
getMarketplaceApps(): Promise<unknown>;
|
|
25
|
+
createMapper(sourceMarketplaceApps: any, targetMarketplaceApps: any): void;
|
|
26
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const utils_1 = require("../../utils");
|
|
4
|
+
const path_1 = require("path");
|
|
5
|
+
const lodash_1 = require("lodash");
|
|
6
|
+
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
7
|
+
class marketplaceAppImportSetup {
|
|
8
|
+
constructor({ config, stackAPIClient }) {
|
|
9
|
+
this.config = config;
|
|
10
|
+
this.stackAPIClient = stackAPIClient;
|
|
11
|
+
this.marketplaceAppsFilePath = (0, path_1.join)((0, cli_utilities_1.sanitizePath)(this.config.contentDir), 'marketplace_apps', 'marketplace_apps.json');
|
|
12
|
+
this.marketplaceAppsConfig = config.modules['marketplace-apps'];
|
|
13
|
+
this.marketplaceAppsUidMapperPath = (0, path_1.join)((0, cli_utilities_1.sanitizePath)(this.config.backupDir), 'mapper', 'marketplace_apps');
|
|
14
|
+
this.marketplaceAppMapper = { app_uid: {}, installation_uid: {}, extension_uid: {} };
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Start the marketplaceApp import setup
|
|
18
|
+
* This method reads the marketplaceApps from the content folder and generates a mapper file
|
|
19
|
+
* @returns {Promise<void>}
|
|
20
|
+
*/
|
|
21
|
+
async start() {
|
|
22
|
+
try {
|
|
23
|
+
const sourceMarketplaceApps = await utils_1.fsUtil.readFile(this.marketplaceAppsFilePath);
|
|
24
|
+
if (!(0, lodash_1.isEmpty)(sourceMarketplaceApps)) {
|
|
25
|
+
utils_1.fsUtil.makeDirectory(this.marketplaceAppsUidMapperPath); // Use fsUtil
|
|
26
|
+
this.developerHubBaseUrl = this.config.developerHubBaseUrl || (await (0, cli_utilities_1.createDeveloperHubUrl)(this.config.host));
|
|
27
|
+
// NOTE init marketplace app sdk
|
|
28
|
+
const host = this.developerHubBaseUrl.split('://').pop();
|
|
29
|
+
this.appSdk = await (0, cli_utilities_1.marketplaceSDKClient)({ host });
|
|
30
|
+
const targetMarketplaceApps = await this.getMarketplaceApps();
|
|
31
|
+
this.createMapper(sourceMarketplaceApps, targetMarketplaceApps);
|
|
32
|
+
await utils_1.fsUtil.writeFile((0, path_1.join)(this.marketplaceAppsUidMapperPath, 'uid-mapping.json'), this.marketplaceAppMapper);
|
|
33
|
+
(0, utils_1.log)(this.config, `Generated required setup files for marketplaceApp`, 'success');
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
(0, utils_1.log)(this.config, 'No marketplaceApps found in the content folder!', 'info');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
(0, utils_1.log)(this.config, `Error generating marketplaceApp mapper: ${(0, cli_utilities_1.formatError)(error)}`, 'error');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async getMarketplaceApps() {
|
|
44
|
+
// Implement this method to get the marketplaceApp from the stack
|
|
45
|
+
return new Promise(async (resolve, reject) => {
|
|
46
|
+
const { items: marketplaceApps = [] } = (await this.appSdk
|
|
47
|
+
.marketplace(this.config.org_uid)
|
|
48
|
+
.installation()
|
|
49
|
+
.fetchAll({ target_uids: this.config.apiKey })
|
|
50
|
+
.catch((error) => {
|
|
51
|
+
reject(error);
|
|
52
|
+
})) || {};
|
|
53
|
+
resolve(marketplaceApps);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
createMapper(sourceMarketplaceApps, targetMarketplaceApps) {
|
|
57
|
+
sourceMarketplaceApps.forEach((sourceApp) => {
|
|
58
|
+
// Find matching target item based on manifest.name
|
|
59
|
+
const targetApp = targetMarketplaceApps.find((targetApp) => (0, lodash_1.get)(targetApp, 'manifest.name') === (0, lodash_1.get)(sourceApp, 'manifest.name'));
|
|
60
|
+
if (targetApp) {
|
|
61
|
+
// Map app_uid from source and target
|
|
62
|
+
this.marketplaceAppMapper.app_uid[sourceApp.manifest.uid] = targetApp.manifest.uid;
|
|
63
|
+
// Map installation_uid from source and target
|
|
64
|
+
this.marketplaceAppMapper.installation_uid[sourceApp.installation_uid] = targetApp.installation_uid;
|
|
65
|
+
// Map extension_uid by comparing meta.uid in source and target's ui_location.locations
|
|
66
|
+
sourceApp.ui_location.locations.forEach((sourceAppLocation) => {
|
|
67
|
+
const targetAppLocation = targetApp.ui_location.locations.find((targetAppLocation) => targetAppLocation.type === sourceAppLocation.type);
|
|
68
|
+
if (targetAppLocation) {
|
|
69
|
+
sourceAppLocation.meta.forEach((sourceAppMeta) => {
|
|
70
|
+
const targetAppMeta = targetAppLocation.meta.find((targetAppMeta) => targetAppMeta.uid === sourceAppMeta.uid);
|
|
71
|
+
if (targetAppMeta && sourceAppMeta.extension_uid && targetAppMeta.extension_uid) {
|
|
72
|
+
this.marketplaceAppMapper.extension_uid[sourceAppMeta.extension_uid] = targetAppMeta.extension_uid;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.default = marketplaceAppImportSetup;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/// <reference types="lodash" />
|
|
2
|
+
import { ModuleClassParams } from '../../types';
|
|
3
|
+
export default class TaxonomiesImportSetup {
|
|
4
|
+
private config;
|
|
5
|
+
private taxonomiesFilePath;
|
|
6
|
+
private stackAPIClient;
|
|
7
|
+
private dependencies;
|
|
8
|
+
private taxonomiesConfig;
|
|
9
|
+
private termsSuccessPath;
|
|
10
|
+
private taxSuccessPath;
|
|
11
|
+
private taxonomiesMapperDirPath;
|
|
12
|
+
private termsMapperDirPath;
|
|
13
|
+
taxonomiesMapper: Record<string, unknown>;
|
|
14
|
+
termsMapper: Record<string, unknown>;
|
|
15
|
+
constructor({ config, stackAPIClient }: ModuleClassParams);
|
|
16
|
+
/**
|
|
17
|
+
* Start the taxonomies import setup
|
|
18
|
+
* This method reads the taxonomies from the content folder and generates a mapper file
|
|
19
|
+
* @returns {Promise<void>}
|
|
20
|
+
*/
|
|
21
|
+
start(): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Retrieves the taxonomies based on the provided taxonomy UID.
|
|
24
|
+
*
|
|
25
|
+
* @param taxonomy - The UID of the taxonomy to retrieve.
|
|
26
|
+
* @returns A promise that resolves to the retrieved taxonomies.
|
|
27
|
+
*/
|
|
28
|
+
getTaxonomies(taxonomy: any): Promise<any>;
|
|
29
|
+
/**
|
|
30
|
+
* Sanitizes the attributes of a taxonomy object.
|
|
31
|
+
*
|
|
32
|
+
* @param taxonomy - The taxonomy object to sanitize.
|
|
33
|
+
* @returns The sanitized taxonomy object with invalid keys omitted.
|
|
34
|
+
*/
|
|
35
|
+
sanitizeTaxonomyAttribs(taxonomy: Record<string, string>): import("lodash").Omit<Record<string, string>, string>;
|
|
36
|
+
/**
|
|
37
|
+
* Retrieves all terms of a taxonomy.
|
|
38
|
+
*
|
|
39
|
+
* @param taxonomy - The taxonomy object.
|
|
40
|
+
* @param skip - The number of terms to skip (default: 0).
|
|
41
|
+
* @param terms - An array to store the retrieved terms (default: []).
|
|
42
|
+
* @returns A promise that resolves to an array of terms.
|
|
43
|
+
*/
|
|
44
|
+
getAllTermsOfTaxonomy(taxonomy: any, skip?: number, terms?: any[]): Promise<any>;
|
|
45
|
+
/**
|
|
46
|
+
* Sanitizes the attributes of the given terms.
|
|
47
|
+
*
|
|
48
|
+
* @param terms - An array of terms to sanitize.
|
|
49
|
+
* @returns The sanitized terms.
|
|
50
|
+
*/
|
|
51
|
+
sanitizeTermsAttribs(terms: Record<string, unknown>[]): Record<string, unknown>[];
|
|
52
|
+
handleTaxonomyErrorMsg(err: any): void;
|
|
53
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const path_1 = require("path");
|
|
5
|
+
const omit_1 = tslib_1.__importDefault(require("lodash/omit"));
|
|
6
|
+
const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
|
|
7
|
+
const utils_1 = require("../../utils");
|
|
8
|
+
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
9
|
+
class TaxonomiesImportSetup {
|
|
10
|
+
constructor({ config, stackAPIClient }) {
|
|
11
|
+
this.taxonomiesMapper = {};
|
|
12
|
+
this.termsMapper = {};
|
|
13
|
+
this.config = config;
|
|
14
|
+
this.stackAPIClient = stackAPIClient;
|
|
15
|
+
this.taxonomiesFilePath = (0, path_1.join)((0, cli_utilities_1.sanitizePath)(this.config.contentDir), 'taxonomies', 'taxonomies.json');
|
|
16
|
+
this.taxonomiesConfig = config.modules.taxonomies;
|
|
17
|
+
this.taxonomiesMapperDirPath = (0, path_1.join)((0, cli_utilities_1.sanitizePath)(this.config.backupDir), 'mapper', 'taxonomies');
|
|
18
|
+
this.taxSuccessPath = (0, path_1.join)((0, cli_utilities_1.sanitizePath)(this.taxonomiesMapperDirPath), 'success.json');
|
|
19
|
+
this.termsMapperDirPath = (0, path_1.join)((0, cli_utilities_1.sanitizePath)(this.taxonomiesMapperDirPath), 'terms');
|
|
20
|
+
this.termsSuccessPath = (0, path_1.join)((0, cli_utilities_1.sanitizePath)(this.termsMapperDirPath), 'success.json');
|
|
21
|
+
this.taxonomiesMapper = {};
|
|
22
|
+
this.termsMapper = {};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Start the taxonomies import setup
|
|
26
|
+
* This method reads the taxonomies from the content folder and generates a mapper file
|
|
27
|
+
* @returns {Promise<void>}
|
|
28
|
+
*/
|
|
29
|
+
async start() {
|
|
30
|
+
try {
|
|
31
|
+
const taxonomies = utils_1.fsUtil.readFile(this.taxonomiesFilePath);
|
|
32
|
+
if (!(0, isEmpty_1.default)(taxonomies)) {
|
|
33
|
+
// 2. Create mapper directory
|
|
34
|
+
utils_1.fsUtil.makeDirectory(this.taxonomiesMapperDirPath);
|
|
35
|
+
utils_1.fsUtil.makeDirectory(this.termsMapperDirPath);
|
|
36
|
+
for (const taxonomy of Object.values(taxonomies)) {
|
|
37
|
+
let targetTaxonomy = await this.getTaxonomies(taxonomy);
|
|
38
|
+
if (!targetTaxonomy) {
|
|
39
|
+
(0, utils_1.log)(this.config, `Taxonomies with uid '${taxonomy.uid}' not found in the stack!`, 'info');
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
targetTaxonomy = this.sanitizeTaxonomyAttribs(targetTaxonomy);
|
|
43
|
+
this.taxonomiesMapper[taxonomy.uid] = targetTaxonomy;
|
|
44
|
+
const terms = await this.getAllTermsOfTaxonomy(targetTaxonomy);
|
|
45
|
+
const sanitizedTerms = this.sanitizeTermsAttribs(terms);
|
|
46
|
+
this.termsMapper[taxonomy.uid] = sanitizedTerms;
|
|
47
|
+
}
|
|
48
|
+
if (this.taxonomiesMapper !== undefined && !(0, isEmpty_1.default)(this.taxonomiesMapper)) {
|
|
49
|
+
utils_1.fsUtil.writeFile(this.taxSuccessPath, this.taxonomiesMapper);
|
|
50
|
+
}
|
|
51
|
+
if (this.termsMapper !== undefined && !(0, isEmpty_1.default)(this.termsMapper)) {
|
|
52
|
+
utils_1.fsUtil.writeFile(this.termsSuccessPath, this.termsMapper);
|
|
53
|
+
}
|
|
54
|
+
(0, utils_1.log)(this.config, `Generated required setup files for taxonomies`, 'success');
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
(0, utils_1.log)(this.config, 'No taxonomies found in the content folder!', 'info');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
(0, utils_1.log)(this.config, `Error generating taxonomies mapper: ${error.message}`, 'error');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Retrieves the taxonomies based on the provided taxonomy UID.
|
|
66
|
+
*
|
|
67
|
+
* @param taxonomy - The UID of the taxonomy to retrieve.
|
|
68
|
+
* @returns A promise that resolves to the retrieved taxonomies.
|
|
69
|
+
*/
|
|
70
|
+
async getTaxonomies(taxonomy) {
|
|
71
|
+
return await this.stackAPIClient
|
|
72
|
+
.taxonomy(taxonomy.uid)
|
|
73
|
+
.fetch()
|
|
74
|
+
.then((data) => data)
|
|
75
|
+
.catch((err) => this.handleTaxonomyErrorMsg(err));
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Sanitizes the attributes of a taxonomy object.
|
|
79
|
+
*
|
|
80
|
+
* @param taxonomy - The taxonomy object to sanitize.
|
|
81
|
+
* @returns The sanitized taxonomy object with invalid keys omitted.
|
|
82
|
+
*/
|
|
83
|
+
sanitizeTaxonomyAttribs(taxonomy) {
|
|
84
|
+
return (0, omit_1.default)(taxonomy, this.taxonomiesConfig.invalidKeys);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Retrieves all terms of a taxonomy.
|
|
88
|
+
*
|
|
89
|
+
* @param taxonomy - The taxonomy object.
|
|
90
|
+
* @param skip - The number of terms to skip (default: 0).
|
|
91
|
+
* @param terms - An array to store the retrieved terms (default: []).
|
|
92
|
+
* @returns A promise that resolves to an array of terms.
|
|
93
|
+
*/
|
|
94
|
+
async getAllTermsOfTaxonomy(taxonomy, skip = 0, terms = []) {
|
|
95
|
+
const queryParams = {
|
|
96
|
+
include_count: true,
|
|
97
|
+
limit: 100,
|
|
98
|
+
skip,
|
|
99
|
+
};
|
|
100
|
+
if (skip >= 0)
|
|
101
|
+
queryParams['skip'] = skip || 0;
|
|
102
|
+
queryParams['depth'] = 0;
|
|
103
|
+
await this.stackAPIClient
|
|
104
|
+
.taxonomy(taxonomy.uid)
|
|
105
|
+
.terms()
|
|
106
|
+
.query(queryParams)
|
|
107
|
+
.find()
|
|
108
|
+
.then((data) => {
|
|
109
|
+
terms = terms.concat(data.items);
|
|
110
|
+
if (data.count >= skip + queryParams.limit) {
|
|
111
|
+
return this.getAllTermsOfTaxonomy(taxonomy, skip + 100, terms);
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
.catch((err) => this.handleTaxonomyErrorMsg(err));
|
|
115
|
+
return terms;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Sanitizes the attributes of the given terms.
|
|
119
|
+
*
|
|
120
|
+
* @param terms - An array of terms to sanitize.
|
|
121
|
+
* @returns The sanitized terms.
|
|
122
|
+
*/
|
|
123
|
+
sanitizeTermsAttribs(terms) {
|
|
124
|
+
for (let index = 0; index < (terms === null || terms === void 0 ? void 0 : terms.length); index++) {
|
|
125
|
+
terms[index] = (0, omit_1.default)(terms[index], this.taxonomiesConfig.invalidKeys);
|
|
126
|
+
}
|
|
127
|
+
return terms;
|
|
128
|
+
}
|
|
129
|
+
handleTaxonomyErrorMsg(err) {
|
|
130
|
+
var _a, _b;
|
|
131
|
+
if ((err === null || err === void 0 ? void 0 : err.errorMessage) || (err === null || err === void 0 ? void 0 : err.message)) {
|
|
132
|
+
const errorMsg = (err === null || err === void 0 ? void 0 : err.errorMessage) || ((_a = err === null || err === void 0 ? void 0 : err.errors) === null || _a === void 0 ? void 0 : _a.taxonomy) || ((_b = err === null || err === void 0 ? void 0 : err.errors) === null || _b === void 0 ? void 0 : _b.term) || (err === null || err === void 0 ? void 0 : err.message);
|
|
133
|
+
(0, utils_1.log)(this.config, errorMsg, 'error');
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
(0, utils_1.log)(this.config, 'Error fetching taxonomy data!', 'error');
|
|
137
|
+
(0, utils_1.log)(this.config, err, 'error');
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
exports.default = TaxonomiesImportSetup;
|