@contentstack/cli-cm-import 1.28.0 → 2.0.0-beta
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 +5 -7
- package/lib/commands/cm/stacks/import.d.ts +2 -0
- package/lib/commands/cm/stacks/import.js +46 -11
- package/lib/config/index.js +0 -1
- package/lib/import/module-importer.d.ts +2 -2
- package/lib/import/module-importer.js +9 -25
- package/lib/import/modules/assets.d.ts +6 -0
- package/lib/import/modules/assets.js +102 -25
- package/lib/import/modules/base-class.d.ts +17 -0
- package/lib/import/modules/base-class.js +45 -0
- package/lib/import/modules/content-types.d.ts +7 -10
- package/lib/import/modules/content-types.js +132 -68
- package/lib/import/modules/custom-roles.d.ts +6 -2
- package/lib/import/modules/custom-roles.js +80 -69
- package/lib/import/modules/entries.d.ts +7 -0
- package/lib/import/modules/entries.js +278 -163
- package/lib/import/modules/environments.d.ts +3 -0
- package/lib/import/modules/environments.js +69 -38
- package/lib/import/modules/extensions.d.ts +3 -0
- package/lib/import/modules/extensions.js +99 -64
- package/lib/import/modules/global-fields.d.ts +8 -1
- package/lib/import/modules/global-fields.js +123 -63
- package/lib/import/modules/index.d.ts +1 -0
- package/lib/import/modules/index.js +1 -0
- package/lib/import/modules/labels.d.ts +3 -0
- package/lib/import/modules/labels.js +104 -54
- package/lib/import/modules/locales.d.ts +15 -4
- package/lib/import/modules/locales.js +194 -94
- package/lib/import/modules/marketplace-apps.d.ts +6 -3
- package/lib/import/modules/marketplace-apps.js +177 -102
- package/lib/import/modules/personalize.d.ts +11 -4
- package/lib/import/modules/personalize.js +138 -47
- package/lib/import/modules/stack.d.ts +6 -0
- package/lib/import/modules/stack.js +71 -27
- package/lib/import/modules/taxonomies.d.ts +4 -2
- package/lib/import/modules/taxonomies.js +60 -46
- package/lib/import/modules/variant-entries.d.ts +7 -4
- package/lib/import/modules/variant-entries.js +76 -35
- package/lib/import/modules/webhooks.d.ts +3 -0
- package/lib/import/modules/webhooks.js +71 -40
- package/lib/import/modules/workflows.d.ts +3 -0
- package/lib/import/modules/workflows.js +98 -48
- package/lib/types/default-config.d.ts +0 -1
- package/lib/types/import-config.d.ts +0 -1
- package/lib/types/index.d.ts +1 -12
- package/lib/utils/backup-handler.js +1 -2
- package/lib/utils/constants.d.ts +243 -0
- package/lib/utils/constants.js +264 -0
- package/lib/utils/import-config-handler.js +2 -7
- package/lib/utils/import-path-resolver.d.ts +1 -1
- package/lib/utils/import-path-resolver.js +5 -5
- package/lib/utils/index.d.ts +1 -1
- package/lib/utils/index.js +6 -2
- package/lib/utils/marketplace-app-helper.js +3 -8
- package/lib/utils/progress-strategy-registry.d.ts +7 -0
- package/lib/utils/progress-strategy-registry.js +72 -0
- package/lib/utils/setup-branch.js +1 -1
- package/oclif.manifest.json +2 -2
- package/package.json +2 -2
- package/lib/import/modules-js/assets.d.ts +0 -33
- package/lib/import/modules-js/assets.js +0 -428
- package/lib/import/modules-js/content-types.d.ts +0 -34
- package/lib/import/modules-js/content-types.js +0 -204
- package/lib/import/modules-js/custom-roles.d.ts +0 -15
- package/lib/import/modules-js/custom-roles.js +0 -143
- package/lib/import/modules-js/entries.d.ts +0 -54
- package/lib/import/modules-js/entries.js +0 -1280
- package/lib/import/modules-js/environments.d.ts +0 -13
- package/lib/import/modules-js/environments.js +0 -85
- package/lib/import/modules-js/extensions.d.ts +0 -18
- package/lib/import/modules-js/extensions.js +0 -86
- package/lib/import/modules-js/global-fields.d.ts +0 -13
- package/lib/import/modules-js/global-fields.js +0 -106
- package/lib/import/modules-js/index.d.ts +0 -1
- package/lib/import/modules-js/index.js +0 -33
- package/lib/import/modules-js/labels.d.ts +0 -20
- package/lib/import/modules-js/labels.js +0 -148
- package/lib/import/modules-js/locales.d.ts +0 -24
- package/lib/import/modules-js/locales.js +0 -196
- package/lib/import/modules-js/marketplace-apps.d.ts +0 -63
- package/lib/import/modules-js/marketplace-apps.js +0 -429
- package/lib/import/modules-js/webhooks.d.ts +0 -17
- package/lib/import/modules-js/webhooks.js +0 -85
- package/lib/import/modules-js/workflows.d.ts +0 -19
- package/lib/import/modules-js/workflows.js +0 -170
- package/lib/utils/log.d.ts +0 -12
- package/lib/utils/log.js +0 -31
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/
|
|
50
|
+
@contentstack/cli-cm-import/2.0.0-beta linux-x64 node-v22.20.0
|
|
51
51
|
$ csdx --help [COMMAND]
|
|
52
52
|
USAGE
|
|
53
53
|
$ csdx COMMAND
|
|
@@ -91,9 +91,8 @@ FLAGS
|
|
|
91
91
|
extensions, marketplace-apps, global-fields, labels, locales, webhooks,
|
|
92
92
|
workflows, custom-roles, personalize projects, and taxonomies.
|
|
93
93
|
-y, --yes [optional] Force override all Marketplace prompts.
|
|
94
|
-
--branch-alias=<value>
|
|
95
|
-
|
|
96
|
-
main branch.
|
|
94
|
+
--branch-alias=<value> Specify the branch alias where you want to import your content. If not
|
|
95
|
+
specified, the content is imported into the main branch by default.
|
|
97
96
|
--exclude-global-modules Excludes the branch-independent module from the import operation.
|
|
98
97
|
--import-webhook-status=<option> [default: disable] [default: disable] (optional) This webhook state keeps the
|
|
99
98
|
same state of webhooks as the source stack. <options: disable|current>
|
|
@@ -160,9 +159,8 @@ FLAGS
|
|
|
160
159
|
extensions, marketplace-apps, global-fields, labels, locales, webhooks,
|
|
161
160
|
workflows, custom-roles, personalize projects, and taxonomies.
|
|
162
161
|
-y, --yes [optional] Force override all Marketplace prompts.
|
|
163
|
-
--branch-alias=<value>
|
|
164
|
-
|
|
165
|
-
main branch.
|
|
162
|
+
--branch-alias=<value> Specify the branch alias where you want to import your content. If not
|
|
163
|
+
specified, the content is imported into the main branch by default.
|
|
166
164
|
--exclude-global-modules Excludes the branch-independent module from the import operation.
|
|
167
165
|
--import-webhook-status=<option> [default: disable] [default: disable] (optional) This webhook state keeps the
|
|
168
166
|
same state of webhooks as the source stack. <options: disable|current>
|
|
@@ -26,6 +26,12 @@ class ImportCommand extends cli_command_1.Command {
|
|
|
26
26
|
if (this.personalizeUrl)
|
|
27
27
|
importConfig.modules.personalize.baseURL[importConfig.region.name] = this.personalizeUrl;
|
|
28
28
|
const managementAPIClient = await (0, cli_utilities_1.managementSDKClient)(importConfig);
|
|
29
|
+
if (flags.branch) {
|
|
30
|
+
cli_utilities_1.CLIProgressManager.initializeGlobalSummary(`IMPORT-${flags.branch}`, flags.branch, `Importing content into "${flags.branch}" branch...`);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
cli_utilities_1.CLIProgressManager.initializeGlobalSummary(`IMPORT`, flags.branch, 'Importing content...');
|
|
34
|
+
}
|
|
29
35
|
const moduleImporter = new import_1.ModuleImporter(managementAPIClient, importConfig);
|
|
30
36
|
const result = await moduleImporter.start();
|
|
31
37
|
backupDir = importConfig.backupDir;
|
|
@@ -35,18 +41,48 @@ class ImportCommand extends cli_command_1.Command {
|
|
|
35
41
|
: `The content has been imported to the stack ${importConfig.apiKey} successfully!`;
|
|
36
42
|
cli_utilities_1.log.success(successMessage, importConfig.context);
|
|
37
43
|
}
|
|
38
|
-
cli_utilities_1.
|
|
39
|
-
|
|
44
|
+
cli_utilities_1.CLIProgressManager.printGlobalSummary();
|
|
45
|
+
this.logSuccessAndBackupMessages(backupDir, importConfig);
|
|
46
|
+
// Clear progress module setting now that import is complete
|
|
47
|
+
(0, cli_utilities_1.clearProgressModuleSetting)();
|
|
40
48
|
}
|
|
41
49
|
catch (error) {
|
|
50
|
+
// Clear progress module setting even on error
|
|
51
|
+
(0, cli_utilities_1.clearProgressModuleSetting)();
|
|
42
52
|
(0, cli_utilities_1.handleAndLogError)(error);
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
53
|
+
this.logAndPrintErrorDetails(error, importConfig);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
logAndPrintErrorDetails(error, importConfig) {
|
|
57
|
+
var _a;
|
|
58
|
+
cli_utilities_1.cliux.print('\n');
|
|
59
|
+
const logPath = (0, cli_utilities_1.getLogPath)();
|
|
60
|
+
const logMsg = `The log has been stored at '${logPath}'`;
|
|
61
|
+
const backupDir = importConfig === null || importConfig === void 0 ? void 0 : importConfig.backupDir;
|
|
62
|
+
const backupDirMsg = backupDir
|
|
63
|
+
? `The backup content has been stored at '${backupDir}'`
|
|
64
|
+
: 'No backup directory was created due to early termination';
|
|
65
|
+
cli_utilities_1.log.info(logMsg);
|
|
66
|
+
cli_utilities_1.log.info(backupDirMsg);
|
|
67
|
+
const showConsoleLogs = (_a = cli_utilities_1.configHandler.get('log')) === null || _a === void 0 ? void 0 : _a.showConsoleLogs;
|
|
68
|
+
if (!showConsoleLogs) {
|
|
69
|
+
cli_utilities_1.cliux.print(`Error: ${error}`, { color: 'red' });
|
|
70
|
+
cli_utilities_1.cliux.print(logMsg, { color: 'blue' });
|
|
71
|
+
cli_utilities_1.cliux.print(backupDirMsg, { color: 'blue' });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
logSuccessAndBackupMessages(backupDir, importConfig) {
|
|
75
|
+
var _a;
|
|
76
|
+
cli_utilities_1.cliux.print('\n');
|
|
77
|
+
const logPath = (0, cli_utilities_1.getLogPath)();
|
|
78
|
+
const logMsg = `The log has been stored at '${logPath}'`;
|
|
79
|
+
const backupDirMsg = `The backup content has been stored at '${backupDir}'`;
|
|
80
|
+
cli_utilities_1.log.success(logMsg, importConfig.context);
|
|
81
|
+
cli_utilities_1.log.info(backupDirMsg, importConfig.context);
|
|
82
|
+
const showConsoleLogs = (_a = cli_utilities_1.configHandler.get('log')) === null || _a === void 0 ? void 0 : _a.showConsoleLogs;
|
|
83
|
+
if (!showConsoleLogs) {
|
|
84
|
+
cli_utilities_1.cliux.print(logMsg, { color: 'blue' });
|
|
85
|
+
cli_utilities_1.cliux.print(backupDirMsg, { color: 'blue' });
|
|
50
86
|
}
|
|
51
87
|
}
|
|
52
88
|
// Create export context object
|
|
@@ -56,7 +92,6 @@ class ImportCommand extends cli_command_1.Command {
|
|
|
56
92
|
command: ((_b = (_a = this.context) === null || _a === void 0 ? void 0 : _a.info) === null || _b === void 0 ? void 0 : _b.command) || 'cm:stacks:import',
|
|
57
93
|
module: '',
|
|
58
94
|
userId: cli_utilities_1.configHandler.get('userUid') || '',
|
|
59
|
-
email: cli_utilities_1.configHandler.get('email') || '',
|
|
60
95
|
sessionId: (_c = this.context) === null || _c === void 0 ? void 0 : _c.sessionId,
|
|
61
96
|
apiKey: apiKey || '',
|
|
62
97
|
orgId: cli_utilities_1.configHandler.get('oauthOrgUid') || '',
|
|
@@ -133,7 +168,7 @@ ImportCommand.flags = {
|
|
|
133
168
|
exclusive: ['branch-alias'],
|
|
134
169
|
}),
|
|
135
170
|
'branch-alias': cli_utilities_1.flags.string({
|
|
136
|
-
description: "
|
|
171
|
+
description: "Specify the branch alias where you want to import your content. If not specified, the content is imported into the main branch by default.",
|
|
137
172
|
exclusive: ['branch'],
|
|
138
173
|
}),
|
|
139
174
|
'import-webhook-status': cli_utilities_1.flags.string({
|
package/lib/config/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ContentstackClient
|
|
1
|
+
import { ContentstackClient } from '@contentstack/cli-utilities';
|
|
2
2
|
import { ImportConfig, Modules } from '../types';
|
|
3
3
|
declare class ModuleImporter {
|
|
4
4
|
private managementAPIClient;
|
|
@@ -20,6 +20,6 @@ declare class ModuleImporter {
|
|
|
20
20
|
* @returns The function `auditImportData()` returns a boolean value. It returns `true` if there is a
|
|
21
21
|
* fix available and the user confirms to proceed with the fix, otherwise it returns `false`.
|
|
22
22
|
*/
|
|
23
|
-
auditImportData(
|
|
23
|
+
auditImportData(): Promise<boolean>;
|
|
24
24
|
}
|
|
25
25
|
export default ModuleImporter;
|
|
@@ -6,7 +6,6 @@ const cli_audit_1 = require("@contentstack/cli-audit");
|
|
|
6
6
|
const messages_1 = tslib_1.__importStar(require("@contentstack/cli-audit/lib/messages"));
|
|
7
7
|
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
8
8
|
const modules_1 = tslib_1.__importDefault(require("./modules"));
|
|
9
|
-
const modules_js_1 = tslib_1.__importDefault(require("./modules-js"));
|
|
10
9
|
const utils_1 = require("../utils");
|
|
11
10
|
class ModuleImporter {
|
|
12
11
|
constructor(managementAPIClient, importConfig) {
|
|
@@ -41,13 +40,11 @@ class ModuleImporter {
|
|
|
41
40
|
// To support the old config
|
|
42
41
|
this.importConfig.data = backupDir;
|
|
43
42
|
}
|
|
44
|
-
// NOTE init log
|
|
45
|
-
const logger = (0, utils_1.initLogger)(this.importConfig);
|
|
46
43
|
// NOTE audit and fix the import content.
|
|
47
44
|
if (!this.importConfig.skipAudit &&
|
|
48
45
|
(!this.importConfig.moduleName ||
|
|
49
46
|
['content-types', 'global-fields', 'entries', 'extensions', 'workflows', 'custom-roles', 'assets'].includes(this.importConfig.moduleName))) {
|
|
50
|
-
if (!(await this.auditImportData(
|
|
47
|
+
if (!(await this.auditImportData())) {
|
|
51
48
|
return { noSuccessMsg: true };
|
|
52
49
|
}
|
|
53
50
|
}
|
|
@@ -60,7 +57,7 @@ class ModuleImporter {
|
|
|
60
57
|
return this.import();
|
|
61
58
|
}
|
|
62
59
|
async import() {
|
|
63
|
-
cli_utilities_1.log.info(`Starting to import
|
|
60
|
+
cli_utilities_1.log.info(`Starting to import`, this.importConfig.context);
|
|
64
61
|
// checks for single module or all modules
|
|
65
62
|
if (this.importConfig.singleModuleImport) {
|
|
66
63
|
return this.importByModuleByName(this.importConfig.moduleName);
|
|
@@ -71,24 +68,11 @@ class ModuleImporter {
|
|
|
71
68
|
cli_utilities_1.log.info(`Starting import of ${moduleName} module`, this.importConfig.context);
|
|
72
69
|
// import the modules by name
|
|
73
70
|
// calls the module runner which inturn calls the module itself
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
moduleName,
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
//NOTE - new modules support only ts
|
|
84
|
-
if (this.importConfig.onlyTSModules.indexOf(moduleName) === -1) {
|
|
85
|
-
return (0, modules_js_1.default)({
|
|
86
|
-
stackAPIClient: this.stackAPIClient,
|
|
87
|
-
importConfig: this.importConfig,
|
|
88
|
-
moduleName,
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
}
|
|
71
|
+
return (0, modules_1.default)({
|
|
72
|
+
stackAPIClient: this.stackAPIClient,
|
|
73
|
+
importConfig: this.importConfig,
|
|
74
|
+
moduleName,
|
|
75
|
+
});
|
|
92
76
|
}
|
|
93
77
|
async importAllModules() {
|
|
94
78
|
// use the algorithm to determine the parallel and sequential execution of modules
|
|
@@ -120,7 +104,7 @@ class ModuleImporter {
|
|
|
120
104
|
* @returns The function `auditImportData()` returns a boolean value. It returns `true` if there is a
|
|
121
105
|
* fix available and the user confirms to proceed with the fix, otherwise it returns `false`.
|
|
122
106
|
*/
|
|
123
|
-
async auditImportData(
|
|
107
|
+
async auditImportData() {
|
|
124
108
|
const basePath = (0, path_1.resolve)(this.importConfig.cliLogsPath || this.importConfig.backupDir, 'logs', 'audit');
|
|
125
109
|
const auditConfig = this.importConfig.auditConfig;
|
|
126
110
|
auditConfig.config.basePath = basePath;
|
|
@@ -151,7 +135,7 @@ class ModuleImporter {
|
|
|
151
135
|
if (result) {
|
|
152
136
|
const { hasFix, config } = result;
|
|
153
137
|
if (hasFix) {
|
|
154
|
-
|
|
138
|
+
cli_utilities_1.log.warn((0, messages_1.$t)(messages_1.default.FINAL_REPORT_PATH, { path: config.reportPath }), this.importConfig.context);
|
|
155
139
|
if (this.importConfig.forceStopMarketplaceAppsPrompt ||
|
|
156
140
|
(await cli_utilities_1.cliux.inquire({
|
|
157
141
|
type: 'confirm',
|
|
@@ -60,4 +60,10 @@ export default class ImportAssets extends BaseClass {
|
|
|
60
60
|
* @returns {Array<Record<string, any>>} Array<Record<string, any>>
|
|
61
61
|
*/
|
|
62
62
|
constructFolderImportOrder(folders: any): Array<Record<string, any>>;
|
|
63
|
+
private analyzeImportData;
|
|
64
|
+
private initializeProgress;
|
|
65
|
+
private countFolders;
|
|
66
|
+
private countAssets;
|
|
67
|
+
private countPublishableAssets;
|
|
68
|
+
private executeStep;
|
|
63
69
|
}
|
|
@@ -24,7 +24,8 @@ class ImportAssets extends base_class_1.default {
|
|
|
24
24
|
this.assetsUidMap = {};
|
|
25
25
|
this.assetsUrlMap = {};
|
|
26
26
|
this.assetsFolderMap = {};
|
|
27
|
-
this.importConfig.context.module =
|
|
27
|
+
this.importConfig.context.module = utils_1.MODULE_CONTEXTS.ASSETS;
|
|
28
|
+
this.currentModuleName = utils_1.MODULE_NAMES[utils_1.MODULE_CONTEXTS.ASSETS];
|
|
28
29
|
this.assetsPath = (0, node_path_1.join)(this.importConfig.backupDir, 'assets');
|
|
29
30
|
this.mapperDirPath = (0, node_path_1.join)(this.importConfig.backupDir, 'mapper', 'assets');
|
|
30
31
|
this.assetUidMapperPath = (0, node_path_1.join)(this.mapperDirPath, 'uid-mapping.json');
|
|
@@ -40,31 +41,35 @@ class ImportAssets extends base_class_1.default {
|
|
|
40
41
|
*/
|
|
41
42
|
async start() {
|
|
42
43
|
try {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
await this.
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
44
|
+
cli_utilities_1.log.debug('Starting assets import process...', this.importConfig.context);
|
|
45
|
+
// Step 1: Analyze import data
|
|
46
|
+
const [foldersCount, assetsCount, versionedAssetsCount, publishableAssetsCount] = await this.withLoadingSpinner('ASSETS: Analyzing import data...', () => this.analyzeImportData());
|
|
47
|
+
// Step 2: Initialize progress tracking
|
|
48
|
+
const progress = this.createNestedProgress(this.currentModuleName);
|
|
49
|
+
this.initializeProgress(progress, {
|
|
50
|
+
foldersCount,
|
|
51
|
+
assetsCount,
|
|
52
|
+
versionedAssetsCount,
|
|
53
|
+
publishableAssetsCount,
|
|
54
|
+
});
|
|
55
|
+
// Step 3: Perform import steps based on data
|
|
56
|
+
if (foldersCount > 0) {
|
|
57
|
+
await this.executeStep(progress, utils_1.PROCESS_NAMES.ASSET_FOLDERS, utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.ASSET_FOLDERS].CREATING, () => this.importFolders());
|
|
58
|
+
}
|
|
59
|
+
if (this.assetConfig.includeVersionedAssets && versionedAssetsCount > 0) {
|
|
60
|
+
await this.executeStep(progress, utils_1.PROCESS_NAMES.ASSET_VERSIONS, utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.ASSET_VERSIONS].IMPORTING, () => this.importAssets(true));
|
|
61
|
+
}
|
|
62
|
+
if (assetsCount > 0) {
|
|
63
|
+
await this.executeStep(progress, utils_1.PROCESS_NAMES.ASSET_UPLOAD, utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.ASSET_UPLOAD].UPLOADING, () => this.importAssets());
|
|
56
64
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
await this.importAssets();
|
|
60
|
-
// NOTE Step 4: Publish assets
|
|
61
|
-
if (!this.importConfig.skipAssetsPublish) {
|
|
62
|
-
cli_utilities_1.log.debug('Starting assets publishing', this.importConfig.context);
|
|
63
|
-
await this.publish();
|
|
65
|
+
if (!this.importConfig.skipAssetsPublish && publishableAssetsCount > 0) {
|
|
66
|
+
await this.executeStep(progress, utils_1.PROCESS_NAMES.ASSET_PUBLISH, utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.ASSET_PUBLISH].PUBLISHING, () => this.publish());
|
|
64
67
|
}
|
|
68
|
+
this.completeProgress(true);
|
|
65
69
|
cli_utilities_1.log.success('Assets imported successfully!', this.importConfig.context);
|
|
66
70
|
}
|
|
67
71
|
catch (error) {
|
|
72
|
+
this.completeProgress(false, (error === null || error === void 0 ? void 0 : error.message) || 'Asset import failed');
|
|
68
73
|
(0, cli_utilities_1.handleAndLogError)(error, Object.assign({}, this.importConfig.context));
|
|
69
74
|
}
|
|
70
75
|
}
|
|
@@ -84,11 +89,15 @@ class ImportAssets extends base_class_1.default {
|
|
|
84
89
|
const batches = this.constructFolderImportOrder(folders);
|
|
85
90
|
cli_utilities_1.log.debug(`Organized folders into ${batches.length} batches for import`, this.importConfig.context);
|
|
86
91
|
const onSuccess = ({ response, apiData: { uid, name } = { uid: null, name: '' } }) => {
|
|
92
|
+
var _a;
|
|
87
93
|
this.assetsFolderMap[uid] = response.uid;
|
|
94
|
+
(_a = this.progressManager) === null || _a === void 0 ? void 0 : _a.tick(true, `folder: ${name || uid}`, null, utils_1.PROCESS_NAMES.ASSET_FOLDERS);
|
|
88
95
|
cli_utilities_1.log.debug(`Created folder: ${name} (Mapped ${uid} → ${response.uid})`, this.importConfig.context);
|
|
89
96
|
cli_utilities_1.log.success(`Created folder: '${name}'`, this.importConfig.context);
|
|
90
97
|
};
|
|
91
|
-
const onReject = ({ error, apiData: { name } = { name: '' } }) => {
|
|
98
|
+
const onReject = ({ error, apiData: { name, uid } = { name: '', uid: '' } }) => {
|
|
99
|
+
var _a;
|
|
100
|
+
(_a = this.progressManager) === null || _a === void 0 ? void 0 : _a.tick(false, `folder: ${name || uid}`, (error === null || error === void 0 ? void 0 : error.message) || utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.ASSET_FOLDERS].FAILED, utils_1.PROCESS_NAMES.ASSET_FOLDERS);
|
|
92
101
|
cli_utilities_1.log.error(`${name} folder creation failed.!`, this.importConfig.context);
|
|
93
102
|
(0, cli_utilities_1.handleAndLogError)(error, Object.assign(Object.assign({}, this.importConfig.context), { name }));
|
|
94
103
|
};
|
|
@@ -134,18 +143,23 @@ class ImportAssets extends base_class_1.default {
|
|
|
134
143
|
const processName = isVersion ? 'import versioned assets' : 'import assets';
|
|
135
144
|
const indexFileName = isVersion ? 'versioned-assets.json' : 'assets.json';
|
|
136
145
|
const basePath = isVersion ? (0, node_path_1.join)(this.assetsPath, 'versions') : this.assetsPath;
|
|
146
|
+
const progressProcessName = isVersion ? utils_1.PROCESS_NAMES.ASSET_VERSIONS : utils_1.PROCESS_NAMES.ASSET_UPLOAD;
|
|
137
147
|
cli_utilities_1.log.debug(`Importing ${processName} from ${basePath}`, this.importConfig.context);
|
|
138
148
|
const fs = new cli_utilities_1.FsUtility({ basePath, indexFileName });
|
|
139
149
|
const indexer = fs.indexFileContent;
|
|
140
150
|
const indexerCount = (0, values_1.default)(indexer).length;
|
|
141
151
|
cli_utilities_1.log.debug(`Found ${indexerCount} asset chunks to process`, this.importConfig.context);
|
|
142
152
|
const onSuccess = ({ response = {}, apiData: { uid, url, title } = undefined }) => {
|
|
153
|
+
var _a;
|
|
143
154
|
this.assetsUidMap[uid] = response.uid;
|
|
144
155
|
this.assetsUrlMap[url] = response.url;
|
|
156
|
+
(_a = this.progressManager) === null || _a === void 0 ? void 0 : _a.tick(true, `asset: ${title || uid}`, null, progressProcessName);
|
|
145
157
|
cli_utilities_1.log.debug(`Created asset: ${title} (Mapped ${uid} → ${response.uid})`, this.importConfig.context);
|
|
146
158
|
cli_utilities_1.log.success(`Created asset: '${title}'`, this.importConfig.context);
|
|
147
159
|
};
|
|
148
|
-
const onReject = ({ error, apiData: { title } = undefined }) => {
|
|
160
|
+
const onReject = ({ error, apiData: { title, uid } = undefined }) => {
|
|
161
|
+
var _a;
|
|
162
|
+
(_a = this.progressManager) === null || _a === void 0 ? void 0 : _a.tick(false, `asset: ${title || uid}`, (error === null || error === void 0 ? void 0 : error.message) || utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.ASSET_UPLOAD].FAILED, progressProcessName);
|
|
149
163
|
cli_utilities_1.log.error(`${title} asset upload failed.!`, this.importConfig.context);
|
|
150
164
|
(0, cli_utilities_1.handleAndLogError)(error, Object.assign(Object.assign({}, this.importConfig.context), { title }));
|
|
151
165
|
};
|
|
@@ -196,12 +210,12 @@ class ImportAssets extends base_class_1.default {
|
|
|
196
210
|
}
|
|
197
211
|
if (!isVersion) {
|
|
198
212
|
if (!(0, isEmpty_1.default)(this.assetsUidMap)) {
|
|
199
|
-
const uidMappingCount = Object.keys(this.assetsUidMap).length;
|
|
213
|
+
const uidMappingCount = Object.keys(this.assetsUidMap || {}).length;
|
|
200
214
|
cli_utilities_1.log.debug(`Writing ${uidMappingCount} UID mappings`, this.importConfig.context);
|
|
201
215
|
this.fs.writeFile(this.assetUidMapperPath, this.assetsUidMap);
|
|
202
216
|
}
|
|
203
217
|
if (!(0, isEmpty_1.default)(this.assetsUrlMap)) {
|
|
204
|
-
const urlMappingCount = Object.keys(this.assetsUrlMap).length;
|
|
218
|
+
const urlMappingCount = Object.keys(this.assetsUrlMap || {}).length;
|
|
205
219
|
cli_utilities_1.log.debug(`Writing ${urlMappingCount} URL mappings`, this.importConfig.context);
|
|
206
220
|
this.fs.writeFile(this.assetUrlMapperPath, this.assetsUrlMap);
|
|
207
221
|
}
|
|
@@ -254,9 +268,13 @@ class ImportAssets extends base_class_1.default {
|
|
|
254
268
|
const indexerCount = (0, values_1.default)(indexer).length;
|
|
255
269
|
cli_utilities_1.log.debug(`Found ${indexerCount} asset chunks to publish`, this.importConfig.context);
|
|
256
270
|
const onSuccess = ({ apiData: { uid, title } = undefined }) => {
|
|
271
|
+
var _a;
|
|
272
|
+
(_a = this.progressManager) === null || _a === void 0 ? void 0 : _a.tick(true, `published: ${title || uid}`, null, utils_1.PROCESS_NAMES.ASSET_PUBLISH);
|
|
257
273
|
cli_utilities_1.log.success(`Asset '${uid}: ${title}' published successfully`, this.importConfig.context);
|
|
258
274
|
};
|
|
259
275
|
const onReject = ({ error, apiData: { uid, title } = undefined }) => {
|
|
276
|
+
var _a;
|
|
277
|
+
(_a = this.progressManager) === null || _a === void 0 ? void 0 : _a.tick(false, `publish failed: ${title || uid}`, (error === null || error === void 0 ? void 0 : error.message) || utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.ASSET_PUBLISH].FAILED, utils_1.PROCESS_NAMES.ASSET_PUBLISH);
|
|
260
278
|
cli_utilities_1.log.error(`Asset '${uid}: ${title}' not published`, this.importConfig.context);
|
|
261
279
|
(0, cli_utilities_1.handleAndLogError)(error, Object.assign(Object.assign({}, this.importConfig.context), { uid, title }));
|
|
262
280
|
};
|
|
@@ -354,5 +372,64 @@ class ImportAssets extends base_class_1.default {
|
|
|
354
372
|
}
|
|
355
373
|
return importOrder;
|
|
356
374
|
}
|
|
375
|
+
async analyzeImportData() {
|
|
376
|
+
const foldersCount = this.countFolders();
|
|
377
|
+
const assetsCount = await this.countAssets(this.assetsPath, 'assets.json');
|
|
378
|
+
let versionedAssetsCount = 0;
|
|
379
|
+
if (this.assetConfig.includeVersionedAssets && (0, node_fs_1.existsSync)(`${this.assetsPath}/versions`)) {
|
|
380
|
+
versionedAssetsCount = await this.countAssets(`${this.assetsPath}/versions`, 'versioned-assets.json');
|
|
381
|
+
}
|
|
382
|
+
let publishableAssetsCount = 0;
|
|
383
|
+
if (!this.importConfig.skipAssetsPublish) {
|
|
384
|
+
publishableAssetsCount = await this.countPublishableAssets();
|
|
385
|
+
}
|
|
386
|
+
cli_utilities_1.log.debug(`Analysis complete: ${foldersCount} folders, ${assetsCount} assets, ${versionedAssetsCount} versioned, ${publishableAssetsCount} publishable`, this.importConfig.context);
|
|
387
|
+
return [foldersCount, assetsCount, versionedAssetsCount, publishableAssetsCount];
|
|
388
|
+
}
|
|
389
|
+
initializeProgress(progress, counts) {
|
|
390
|
+
const { foldersCount, assetsCount, versionedAssetsCount, publishableAssetsCount } = counts;
|
|
391
|
+
if (foldersCount > 0) {
|
|
392
|
+
progress.addProcess(utils_1.PROCESS_NAMES.ASSET_FOLDERS, foldersCount);
|
|
393
|
+
}
|
|
394
|
+
if (versionedAssetsCount > 0) {
|
|
395
|
+
progress.addProcess(utils_1.PROCESS_NAMES.ASSET_VERSIONS, versionedAssetsCount);
|
|
396
|
+
}
|
|
397
|
+
if (assetsCount > 0) {
|
|
398
|
+
progress.addProcess(utils_1.PROCESS_NAMES.ASSET_UPLOAD, assetsCount);
|
|
399
|
+
}
|
|
400
|
+
if (publishableAssetsCount > 0) {
|
|
401
|
+
progress.addProcess(utils_1.PROCESS_NAMES.ASSET_PUBLISH, publishableAssetsCount);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
countFolders() {
|
|
405
|
+
const foldersPath = (0, node_path_1.resolve)(this.assetsRootPath, 'folders.json');
|
|
406
|
+
const folders = this.fs.readFile(foldersPath) || [];
|
|
407
|
+
return Array.isArray(folders) ? folders.length : 0;
|
|
408
|
+
}
|
|
409
|
+
async countAssets(basePath, indexFileName) {
|
|
410
|
+
const fsUtil = new cli_utilities_1.FsUtility({ basePath, indexFileName });
|
|
411
|
+
let count = 0;
|
|
412
|
+
for (const _ of (0, values_1.default)(fsUtil.indexFileContent)) {
|
|
413
|
+
const chunkData = await fsUtil.readChunkFiles.next().catch(() => ({}));
|
|
414
|
+
count += (0, values_1.default)(chunkData).length;
|
|
415
|
+
}
|
|
416
|
+
return count;
|
|
417
|
+
}
|
|
418
|
+
async countPublishableAssets() {
|
|
419
|
+
const fsUtil = new cli_utilities_1.FsUtility({ basePath: this.assetsPath, indexFileName: 'assets.json' });
|
|
420
|
+
let count = 0;
|
|
421
|
+
for (const _ of (0, values_1.default)(fsUtil.indexFileContent)) {
|
|
422
|
+
const chunkData = await fsUtil.readChunkFiles.next().catch(() => ({}));
|
|
423
|
+
const publishableAssets = (0, filter_1.default)((0, values_1.default)(chunkData), ({ publish_details }) => !(0, isEmpty_1.default)(publish_details));
|
|
424
|
+
count += publishableAssets.length;
|
|
425
|
+
}
|
|
426
|
+
return count;
|
|
427
|
+
}
|
|
428
|
+
async executeStep(progress, name, status, action) {
|
|
429
|
+
progress.startProcess(name).updateStatus(status, name);
|
|
430
|
+
cli_utilities_1.log.debug(`Starting ${name.toLowerCase()}`, this.importConfig.context);
|
|
431
|
+
await action();
|
|
432
|
+
progress.completeProcess(name, true);
|
|
433
|
+
}
|
|
357
434
|
}
|
|
358
435
|
exports.default = ImportAssets;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Stack } from '@contentstack/management/types/stack';
|
|
2
|
+
import { CLIProgressManager } from '@contentstack/cli-utilities';
|
|
2
3
|
import { ImportConfig, ModuleClassParams } from '../../types';
|
|
3
4
|
export type AdditionalKeys = {
|
|
4
5
|
backupDir: string;
|
|
@@ -36,8 +37,24 @@ export default abstract class BaseClass {
|
|
|
36
37
|
readonly client: Stack;
|
|
37
38
|
importConfig: ImportConfig;
|
|
38
39
|
modulesConfig: any;
|
|
40
|
+
protected progressManager: CLIProgressManager | null;
|
|
41
|
+
protected currentModuleName: string;
|
|
39
42
|
constructor({ importConfig, stackAPIClient }: Omit<ModuleClassParams, 'moduleName'>);
|
|
40
43
|
get stack(): Stack;
|
|
44
|
+
static printFinalSummary(): void;
|
|
45
|
+
/**
|
|
46
|
+
* Create simple progress manager
|
|
47
|
+
*/
|
|
48
|
+
protected createSimpleProgress(moduleName: string, total?: number): CLIProgressManager;
|
|
49
|
+
/**
|
|
50
|
+
* Create nested progress manager
|
|
51
|
+
*/
|
|
52
|
+
protected createNestedProgress(moduleName: string): CLIProgressManager;
|
|
53
|
+
/**
|
|
54
|
+
* Complete progress manager
|
|
55
|
+
*/
|
|
56
|
+
protected completeProgress(success?: boolean, error?: string): void;
|
|
57
|
+
protected withLoadingSpinner<T>(message: string, action: () => Promise<T>): Promise<T>;
|
|
41
58
|
/**
|
|
42
59
|
* @method delay
|
|
43
60
|
* @param {number} ms number
|
|
@@ -12,6 +12,8 @@ const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
|
12
12
|
const cloneDeep_1 = tslib_1.__importDefault(require("lodash/cloneDeep"));
|
|
13
13
|
class BaseClass {
|
|
14
14
|
constructor({ importConfig, stackAPIClient }) {
|
|
15
|
+
this.progressManager = null;
|
|
16
|
+
this.currentModuleName = '';
|
|
15
17
|
this.client = stackAPIClient;
|
|
16
18
|
this.importConfig = importConfig;
|
|
17
19
|
this.modulesConfig = importConfig.modules;
|
|
@@ -19,6 +21,49 @@ class BaseClass {
|
|
|
19
21
|
get stack() {
|
|
20
22
|
return this.client;
|
|
21
23
|
}
|
|
24
|
+
static printFinalSummary() {
|
|
25
|
+
cli_utilities_1.CLIProgressManager.printGlobalSummary();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Create simple progress manager
|
|
29
|
+
*/
|
|
30
|
+
createSimpleProgress(moduleName, total) {
|
|
31
|
+
var _a;
|
|
32
|
+
this.currentModuleName = moduleName;
|
|
33
|
+
const logConfig = cli_utilities_1.configHandler.get('log') || {};
|
|
34
|
+
const showConsoleLogs = (_a = logConfig.showConsoleLogs) !== null && _a !== void 0 ? _a : false; // Default to true for better UX
|
|
35
|
+
this.progressManager = cli_utilities_1.CLIProgressManager.createSimple(moduleName, total, showConsoleLogs);
|
|
36
|
+
return this.progressManager;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Create nested progress manager
|
|
40
|
+
*/
|
|
41
|
+
createNestedProgress(moduleName) {
|
|
42
|
+
var _a;
|
|
43
|
+
this.currentModuleName = moduleName;
|
|
44
|
+
const logConfig = cli_utilities_1.configHandler.get('log') || {};
|
|
45
|
+
const showConsoleLogs = (_a = logConfig.showConsoleLogs) !== null && _a !== void 0 ? _a : false; // Default to true for better UX
|
|
46
|
+
this.progressManager = cli_utilities_1.CLIProgressManager.createNested(moduleName, showConsoleLogs);
|
|
47
|
+
return this.progressManager;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Complete progress manager
|
|
51
|
+
*/
|
|
52
|
+
completeProgress(success = true, error) {
|
|
53
|
+
var _a;
|
|
54
|
+
(_a = this.progressManager) === null || _a === void 0 ? void 0 : _a.complete(success, error);
|
|
55
|
+
this.progressManager = null;
|
|
56
|
+
}
|
|
57
|
+
async withLoadingSpinner(message, action) {
|
|
58
|
+
var _a;
|
|
59
|
+
const logConfig = cli_utilities_1.configHandler.get('log') || {};
|
|
60
|
+
const showConsoleLogs = (_a = logConfig.showConsoleLogs) !== null && _a !== void 0 ? _a : false;
|
|
61
|
+
if (showConsoleLogs) {
|
|
62
|
+
// If console logs are enabled, don't show spinner, just execute the action
|
|
63
|
+
return await action();
|
|
64
|
+
}
|
|
65
|
+
return await cli_utilities_1.CLIProgressManager.withLoadingSpinner(message, action);
|
|
66
|
+
}
|
|
22
67
|
/**
|
|
23
68
|
* @method delay
|
|
24
69
|
* @param {number} ms number
|
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Contentstack Import
|
|
3
|
-
* Copyright (c) 2024 Contentstack LLC
|
|
4
|
-
* MIT Licensed
|
|
5
|
-
*/
|
|
6
1
|
import { ModuleClassParams } from '../../types';
|
|
7
2
|
import BaseClass, { ApiOptions } from './base-class';
|
|
8
3
|
export default class ContentTypesImport extends BaseClass {
|
|
9
4
|
private cTsMapperPath;
|
|
10
5
|
private cTsFolderPath;
|
|
11
|
-
private cTsFailsPath;
|
|
12
6
|
private cTsSuccessPath;
|
|
13
7
|
private gFsPendingPath;
|
|
14
8
|
private pendingGFs;
|
|
@@ -16,12 +10,8 @@ export default class ContentTypesImport extends BaseClass {
|
|
|
16
10
|
private gFsFolderPath;
|
|
17
11
|
private gFsMapperFolderPath;
|
|
18
12
|
private gFs;
|
|
19
|
-
private failedCTs;
|
|
20
13
|
private createdCTs;
|
|
21
14
|
private cTs;
|
|
22
|
-
private cTsUidMapper;
|
|
23
|
-
private config;
|
|
24
|
-
private stackAPIClient;
|
|
25
15
|
private marketplaceAppMapperPath;
|
|
26
16
|
private reqConcurrency;
|
|
27
17
|
private ignoredFilesInContentTypesFolder;
|
|
@@ -34,6 +24,7 @@ export default class ContentTypesImport extends BaseClass {
|
|
|
34
24
|
taxonomies: Record<string, unknown>;
|
|
35
25
|
private extPendingPath;
|
|
36
26
|
private isExtensionsUpdate;
|
|
27
|
+
private pendingExts;
|
|
37
28
|
constructor({ importConfig, stackAPIClient }: ModuleClassParams);
|
|
38
29
|
start(): Promise<any>;
|
|
39
30
|
seedCTs(): Promise<any>;
|
|
@@ -58,4 +49,10 @@ export default class ContentTypesImport extends BaseClass {
|
|
|
58
49
|
*/
|
|
59
50
|
serializeUpdateGFs(apiOptions: ApiOptions): ApiOptions;
|
|
60
51
|
updatePendingExtensions(): Promise<any>;
|
|
52
|
+
analyzeImportData(): Promise<void>;
|
|
53
|
+
initializeProgress(): import("@contentstack/cli-utilities").CLIProgressManager;
|
|
54
|
+
handlePendingGlobalFields(progress: any): Promise<void>;
|
|
55
|
+
handleContentTypesCreation(progress: any): Promise<void>;
|
|
56
|
+
handleContentTypesUpdate(progress: any): Promise<void>;
|
|
57
|
+
handlePendingExtensions(progress: any): Promise<void>;
|
|
61
58
|
}
|