@contentstack/cli-cm-import 1.26.3 → 1.28.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 +7 -1
- package/lib/commands/cm/stacks/import.js +5 -20
- package/lib/import/module-importer.d.ts +5 -0
- package/lib/import/module-importer.js +30 -26
- package/lib/import/modules/base-class.js +3 -2
- package/lib/import/modules/entries.js +3 -3
- package/lib/types/import-config.d.ts +1 -0
- package/lib/utils/backup-handler.js +7 -5
- package/lib/utils/import-config-handler.js +3 -0
- package/lib/utils/import-path-resolver.d.ts +29 -0
- package/lib/utils/import-path-resolver.js +134 -0
- package/lib/utils/index.d.ts +2 -0
- package/lib/utils/index.js +8 -1
- package/lib/utils/interactive.d.ts +1 -0
- package/lib/utils/interactive.js +10 -1
- package/lib/utils/setup-branch.d.ts +3 -0
- package/lib/utils/setup-branch.js +31 -0
- package/oclif.manifest.json +14 -1
- package/package.json +5 -5
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.
|
|
50
|
+
@contentstack/cli-cm-import/1.28.0 linux-x64 node-v22.19.0
|
|
51
51
|
$ csdx --help [COMMAND]
|
|
52
52
|
USAGE
|
|
53
53
|
$ csdx COMMAND
|
|
@@ -91,6 +91,9 @@ 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> The alias of the branch where you want to import your content. If you don't
|
|
95
|
+
mention the branch alias, then by default the content will be imported to the
|
|
96
|
+
main branch.
|
|
94
97
|
--exclude-global-modules Excludes the branch-independent module from the import operation.
|
|
95
98
|
--import-webhook-status=<option> [default: disable] [default: disable] (optional) This webhook state keeps the
|
|
96
99
|
same state of webhooks as the source stack. <options: disable|current>
|
|
@@ -157,6 +160,9 @@ FLAGS
|
|
|
157
160
|
extensions, marketplace-apps, global-fields, labels, locales, webhooks,
|
|
158
161
|
workflows, custom-roles, personalize projects, and taxonomies.
|
|
159
162
|
-y, --yes [optional] Force override all Marketplace prompts.
|
|
163
|
+
--branch-alias=<value> The alias of the branch where you want to import your content. If you don't
|
|
164
|
+
mention the branch alias, then by default the content will be imported to the
|
|
165
|
+
main branch.
|
|
160
166
|
--exclude-global-modules Excludes the branch-independent module from the import operation.
|
|
161
167
|
--import-webhook-status=<option> [default: disable] [default: disable] (optional) This webhook state keeps the
|
|
162
168
|
same state of webhooks as the source stack. <options: disable|current>
|
|
@@ -26,26 +26,6 @@ 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
|
-
try {
|
|
31
|
-
// Use stack configuration to check for branch availability
|
|
32
|
-
// false positive - no hardcoded secret here
|
|
33
|
-
// @ts-ignore-next-line secret-detection
|
|
34
|
-
const keyProp = 'api_key';
|
|
35
|
-
const branches = await managementAPIClient
|
|
36
|
-
.stack({ [keyProp]: importConfig.apiKey })
|
|
37
|
-
.branch()
|
|
38
|
-
.query()
|
|
39
|
-
.find()
|
|
40
|
-
.then(({ items }) => items);
|
|
41
|
-
if (branches.length) {
|
|
42
|
-
flags.branch = 'main';
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
// Branch not enabled, just the let flow continue
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
29
|
const moduleImporter = new import_1.ModuleImporter(managementAPIClient, importConfig);
|
|
50
30
|
const result = await moduleImporter.start();
|
|
51
31
|
backupDir = importConfig.backupDir;
|
|
@@ -150,6 +130,11 @@ ImportCommand.flags = {
|
|
|
150
130
|
char: 'B',
|
|
151
131
|
description: "The name of the branch where you want to import your content. If you don't mention the branch name, then by default the content will be imported to the main branch.",
|
|
152
132
|
parse: (0, cli_utilities_1.printFlagDeprecation)(['-B'], ['--branch']),
|
|
133
|
+
exclusive: ['branch-alias'],
|
|
134
|
+
}),
|
|
135
|
+
'branch-alias': cli_utilities_1.flags.string({
|
|
136
|
+
description: "The alias of the branch where you want to import your content. If you don't mention the branch alias, then by default the content will be imported to the main branch.",
|
|
137
|
+
exclusive: ['branch'],
|
|
153
138
|
}),
|
|
154
139
|
'import-webhook-status': cli_utilities_1.flags.string({
|
|
155
140
|
description: '[default: disable] (optional) This webhook state keeps the same state of webhooks as the source stack. <options: disable|current>',
|
|
@@ -9,6 +9,11 @@ declare class ModuleImporter {
|
|
|
9
9
|
import(): Promise<any>;
|
|
10
10
|
importByModuleByName(moduleName: Modules): Promise<any>;
|
|
11
11
|
importAllModules(): Promise<any>;
|
|
12
|
+
/**
|
|
13
|
+
* Resolves the import path based on directory structure and user configuration
|
|
14
|
+
* @returns Promise<void>
|
|
15
|
+
*/
|
|
16
|
+
private resolveImportPath;
|
|
12
17
|
/**
|
|
13
18
|
* The `auditImportData` function performs an audit process on imported data, using a specified
|
|
14
19
|
* configuration, and returns a boolean indicating whether a fix is needed.
|
|
@@ -23,8 +23,14 @@ class ModuleImporter {
|
|
|
23
23
|
this.importConfig.stackName = stackDetails.name;
|
|
24
24
|
this.importConfig.org_uid = stackDetails.org_uid;
|
|
25
25
|
}
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
await this.resolveImportPath();
|
|
27
|
+
await (0, utils_1.setupBranchConfig)(this.importConfig, this.stackAPIClient);
|
|
28
|
+
if (this.importConfig.branchAlias && this.importConfig.branchName) {
|
|
29
|
+
this.stackAPIClient = this.managementAPIClient.stack({
|
|
30
|
+
api_key: this.importConfig.apiKey,
|
|
31
|
+
management_token: this.importConfig.management_token,
|
|
32
|
+
branch_uid: this.importConfig.branchName,
|
|
33
|
+
});
|
|
28
34
|
}
|
|
29
35
|
if (this.importConfig.management_token) {
|
|
30
36
|
await (0, cli_utilities_1.addLocale)(this.importConfig.apiKey, this.importConfig.management_token, this.importConfig.host);
|
|
@@ -40,15 +46,7 @@ class ModuleImporter {
|
|
|
40
46
|
// NOTE audit and fix the import content.
|
|
41
47
|
if (!this.importConfig.skipAudit &&
|
|
42
48
|
(!this.importConfig.moduleName ||
|
|
43
|
-
[
|
|
44
|
-
'content-types',
|
|
45
|
-
'global-fields',
|
|
46
|
-
'entries',
|
|
47
|
-
'extensions',
|
|
48
|
-
'workflows',
|
|
49
|
-
'custom-roles',
|
|
50
|
-
'assets'
|
|
51
|
-
].includes(this.importConfig.moduleName))) {
|
|
49
|
+
['content-types', 'global-fields', 'entries', 'extensions', 'workflows', 'custom-roles', 'assets'].includes(this.importConfig.moduleName))) {
|
|
52
50
|
if (!(await this.auditImportData(logger))) {
|
|
53
51
|
return { noSuccessMsg: true };
|
|
54
52
|
}
|
|
@@ -62,7 +60,7 @@ class ModuleImporter {
|
|
|
62
60
|
return this.import();
|
|
63
61
|
}
|
|
64
62
|
async import() {
|
|
65
|
-
|
|
63
|
+
cli_utilities_1.log.info(`Starting to import content version ${this.importConfig.contentVersion}`, this.importConfig.context);
|
|
66
64
|
// checks for single module or all modules
|
|
67
65
|
if (this.importConfig.singleModuleImport) {
|
|
68
66
|
return this.importByModuleByName(this.importConfig.moduleName);
|
|
@@ -70,7 +68,7 @@ class ModuleImporter {
|
|
|
70
68
|
return this.importAllModules();
|
|
71
69
|
}
|
|
72
70
|
async importByModuleByName(moduleName) {
|
|
73
|
-
|
|
71
|
+
cli_utilities_1.log.info(`Starting import of ${moduleName} module`, this.importConfig.context);
|
|
74
72
|
// import the modules by name
|
|
75
73
|
// calls the module runner which inturn calls the module itself
|
|
76
74
|
// NOTE: Implement a mechanism to determine whether module is new or old
|
|
@@ -96,12 +94,26 @@ class ModuleImporter {
|
|
|
96
94
|
// use the algorithm to determine the parallel and sequential execution of modules
|
|
97
95
|
for (let moduleName of this.importConfig.modules.types) {
|
|
98
96
|
if (this.importConfig.globalModules.includes(moduleName) && this.importConfig['exclude-global-modules']) {
|
|
99
|
-
|
|
97
|
+
cli_utilities_1.log.warn(`Skipping the import of the global module '${moduleName}', as it already exists in the stack.`, this.importConfig.context);
|
|
100
98
|
continue;
|
|
101
99
|
}
|
|
102
100
|
await this.importByModuleByName(moduleName);
|
|
103
101
|
}
|
|
104
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Resolves the import path based on directory structure and user configuration
|
|
105
|
+
* @returns Promise<void>
|
|
106
|
+
*/
|
|
107
|
+
async resolveImportPath() {
|
|
108
|
+
try {
|
|
109
|
+
const resolvedPath = await (0, utils_1.executeImportPathLogic)(this.importConfig, this.stackAPIClient);
|
|
110
|
+
cli_utilities_1.log.debug(`Import path resolved to: ${resolvedPath}`);
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
cli_utilities_1.log.error(`Failed to resolve import path: ${error}`);
|
|
114
|
+
// Continue with original path if resolution fails
|
|
115
|
+
}
|
|
116
|
+
}
|
|
105
117
|
/**
|
|
106
118
|
* The `auditImportData` function performs an audit process on imported data, using a specified
|
|
107
119
|
* configuration, and returns a boolean indicating whether a fix is needed.
|
|
@@ -127,23 +139,15 @@ class ModuleImporter {
|
|
|
127
139
|
}
|
|
128
140
|
else if (this.importConfig.modules.types.length) {
|
|
129
141
|
this.importConfig.modules.types
|
|
130
|
-
.filter((val) => [
|
|
131
|
-
'content-types',
|
|
132
|
-
'global-fields',
|
|
133
|
-
'entries',
|
|
134
|
-
'extensions',
|
|
135
|
-
'workflows',
|
|
136
|
-
'custom-roles',
|
|
137
|
-
'assets'
|
|
138
|
-
].includes(val))
|
|
142
|
+
.filter((val) => ['content-types', 'global-fields', 'entries', 'extensions', 'workflows', 'custom-roles', 'assets'].includes(val))
|
|
139
143
|
.forEach((val) => {
|
|
140
144
|
args.push('--modules', val);
|
|
141
145
|
});
|
|
142
146
|
}
|
|
143
147
|
args.push('--modules', 'field-rules');
|
|
144
|
-
|
|
148
|
+
cli_utilities_1.log.info('Starting audit process', this.importConfig.context);
|
|
145
149
|
const result = await cli_audit_1.AuditFix.run(args);
|
|
146
|
-
|
|
150
|
+
cli_utilities_1.log.info('Audit process completed', this.importConfig.context);
|
|
147
151
|
if (result) {
|
|
148
152
|
const { hasFix, config } = result;
|
|
149
153
|
if (hasFix) {
|
|
@@ -162,7 +166,7 @@ class ModuleImporter {
|
|
|
162
166
|
return true;
|
|
163
167
|
}
|
|
164
168
|
catch (error) {
|
|
165
|
-
|
|
169
|
+
cli_utilities_1.log.error(`Audit failed with following error. ${error}`, this.importConfig.context);
|
|
166
170
|
}
|
|
167
171
|
}
|
|
168
172
|
}
|
|
@@ -8,7 +8,7 @@ const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
|
|
|
8
8
|
const entries_1 = tslib_1.__importDefault(require("lodash/entries"));
|
|
9
9
|
const isEqual_1 = tslib_1.__importDefault(require("lodash/isEqual"));
|
|
10
10
|
const omit_1 = tslib_1.__importDefault(require("lodash/omit"));
|
|
11
|
-
const
|
|
11
|
+
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 }) {
|
|
@@ -84,6 +84,7 @@ class BaseClass {
|
|
|
84
84
|
* @returns {Promise} Promise<void>
|
|
85
85
|
*/
|
|
86
86
|
async logMsgAndWaitIfRequired(processName, start, totelBatches, batchNo, logBatchCompletionMsg = true, indexerCount, currentIndexer) {
|
|
87
|
+
var _a;
|
|
87
88
|
const end = Date.now();
|
|
88
89
|
const exeTime = end - start;
|
|
89
90
|
if (logBatchCompletionMsg) {
|
|
@@ -91,7 +92,7 @@ class BaseClass {
|
|
|
91
92
|
// info: Batch No. 20 of import assets is complete
|
|
92
93
|
if (currentIndexer)
|
|
93
94
|
batchMsg += `Current chunk processing is (${currentIndexer}/${indexerCount})`;
|
|
94
|
-
|
|
95
|
+
cli_utilities_1.log.debug(`Batch No. (${batchNo}/${totelBatches}) of ${processName} is complete`, (_a = this.importConfig) === null || _a === void 0 ? void 0 : _a.context);
|
|
95
96
|
}
|
|
96
97
|
if (this.importConfig.modules.assets.displayExecutionTime) {
|
|
97
98
|
console.log(`Time taken to execute: ${exeTime} milliseconds; wait time: ${exeTime < 1000 ? 1000 - exeTime : 0} milliseconds`);
|
|
@@ -158,11 +158,11 @@ class EntriesImport extends base_class_1.default {
|
|
|
158
158
|
async disableMandatoryCTReferences() {
|
|
159
159
|
cli_utilities_1.log.debug(`Starting to disable mandatory CT references for ${this.cTs.length} content types`, this.importConfig.context);
|
|
160
160
|
const onSuccess = ({ response: contentType, apiData: { uid } }) => {
|
|
161
|
-
cli_utilities_1.log.success(
|
|
162
|
-
cli_utilities_1.log.debug(`Successfully processed content type: ${uid}`, this.importConfig.context);
|
|
161
|
+
cli_utilities_1.log.success(`'${uid}' content type references removed temporarily`, this.importConfig.context);
|
|
162
|
+
cli_utilities_1.log.debug(`Successfully processed content type: '${uid}'`, this.importConfig.context);
|
|
163
163
|
};
|
|
164
164
|
const onReject = ({ error, apiData: { uid } }) => {
|
|
165
|
-
(0, cli_utilities_1.handleAndLogError)(error, Object.assign(Object.assign({}, this.importConfig.context), { uid }),
|
|
165
|
+
(0, cli_utilities_1.handleAndLogError)(error, Object.assign(Object.assign({}, this.importConfig.context), { uid }), `'${uid}' content type references removal failed`);
|
|
166
166
|
};
|
|
167
167
|
return await this.makeConcurrentCall({
|
|
168
168
|
processName: 'Update content types (removing mandatory references temporarily)',
|
|
@@ -11,10 +11,12 @@ async function backupHandler(importConfig) {
|
|
|
11
11
|
cli_utilities_1.log.debug(`Using existing backup directory: ${importConfig.useBackedupDir}`);
|
|
12
12
|
return importConfig.useBackedupDir;
|
|
13
13
|
}
|
|
14
|
+
const sourceDir = importConfig.branchDir || importConfig.contentDir;
|
|
15
|
+
cli_utilities_1.log.debug(`Using source directory for backup: ${sourceDir} (branchDir: ${importConfig.branchDir}, contentDir: ${importConfig.contentDir})`);
|
|
14
16
|
let backupDirPath;
|
|
15
|
-
const subDir = isSubDirectory(importConfig);
|
|
17
|
+
const subDir = isSubDirectory(importConfig, sourceDir);
|
|
16
18
|
if (subDir) {
|
|
17
|
-
backupDirPath = path.resolve((0, cli_utilities_1.sanitizePath)(
|
|
19
|
+
backupDirPath = path.resolve((0, cli_utilities_1.sanitizePath)(sourceDir), '..', '_backup_' + Math.floor(Math.random() * 1000));
|
|
18
20
|
cli_utilities_1.log.debug(`Detected subdirectory configuration, creating backup at: ${backupDirPath}`);
|
|
19
21
|
if (importConfig.createBackupDir) {
|
|
20
22
|
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}`, {
|
|
@@ -41,7 +43,7 @@ async function backupHandler(importConfig) {
|
|
|
41
43
|
cli_utilities_1.log.debug(`Starting content copy to backup directory: ${backupDirPath}`);
|
|
42
44
|
cli_utilities_1.cliux.print('Copying content to the backup directory...');
|
|
43
45
|
return new Promise((resolve, reject) => {
|
|
44
|
-
return (0, fs_extra_1.copy)(
|
|
46
|
+
return (0, fs_extra_1.copy)(sourceDir, backupDirPath, (error) => {
|
|
45
47
|
if (error) {
|
|
46
48
|
(0, index_1.trace)(error, 'error', true);
|
|
47
49
|
return reject(error);
|
|
@@ -58,9 +60,9 @@ exports.default = backupHandler;
|
|
|
58
60
|
* @param importConfig
|
|
59
61
|
* @returns
|
|
60
62
|
*/
|
|
61
|
-
function isSubDirectory(importConfig) {
|
|
63
|
+
function isSubDirectory(importConfig, sourceDir) {
|
|
62
64
|
cli_utilities_1.log.debug('Checking if backup directory is a subdirectory');
|
|
63
|
-
const parent =
|
|
65
|
+
const parent = sourceDir;
|
|
64
66
|
const child = importConfig.createBackupDir ? importConfig.createBackupDir : process.cwd();
|
|
65
67
|
const relative = path.relative(parent, child);
|
|
66
68
|
cli_utilities_1.log.debug(`Parent directory: ${parent}, Child directory: ${child}, Relative path: ${relative}`);
|
|
@@ -92,6 +92,9 @@ const setupConfig = async (importCmdFlags) => {
|
|
|
92
92
|
config.forceStopMarketplaceAppsPrompt = importCmdFlags.yes;
|
|
93
93
|
config.importWebhookStatus = importCmdFlags['import-webhook-status'];
|
|
94
94
|
config.skipPrivateAppRecreationIfExist = !importCmdFlags['skip-app-recreation'];
|
|
95
|
+
if (importCmdFlags['branch-alias']) {
|
|
96
|
+
config.branchAlias = importCmdFlags['branch-alias'];
|
|
97
|
+
}
|
|
95
98
|
if (importCmdFlags['branch']) {
|
|
96
99
|
config.branchName = importCmdFlags['branch'];
|
|
97
100
|
config.branchDir = config.contentDir;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ImportConfig } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Selects a branch from directory structure when multiple branches are found
|
|
4
|
+
* @param contentDir - The content directory path
|
|
5
|
+
* @returns Promise<{ branchPath: string } | null>
|
|
6
|
+
*/
|
|
7
|
+
export declare const selectBranchFromDirectory: (contentDir: string) => Promise<{
|
|
8
|
+
branchPath: string;
|
|
9
|
+
} | null>;
|
|
10
|
+
/**
|
|
11
|
+
* Resolves the import path based on directory structure and user configuration
|
|
12
|
+
* @param importConfig - The import configuration object
|
|
13
|
+
* @param stackAPIClient - The Contentstack API client
|
|
14
|
+
* @returns Promise<string> - The resolved path
|
|
15
|
+
*/
|
|
16
|
+
export declare const resolveImportPath: (importConfig: ImportConfig, stackAPIClient: any) => Promise<string>;
|
|
17
|
+
/**
|
|
18
|
+
* Updates the import configuration with the resolved path
|
|
19
|
+
* @param importConfig - The import configuration object
|
|
20
|
+
* @param resolvedPath - The resolved path
|
|
21
|
+
*/
|
|
22
|
+
export declare const updateImportConfigWithResolvedPath: (importConfig: ImportConfig, resolvedPath: string) => void;
|
|
23
|
+
/**
|
|
24
|
+
* Executes the complete import path resolution logic
|
|
25
|
+
* @param importConfig - The import configuration object
|
|
26
|
+
* @param stackAPIClient - The Contentstack API client
|
|
27
|
+
* @returns Promise<string> - The resolved path
|
|
28
|
+
*/
|
|
29
|
+
export declare const executeImportPathLogic: (importConfig: ImportConfig, stackAPIClient: any) => Promise<string>;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.executeImportPathLogic = exports.updateImportConfigWithResolvedPath = exports.resolveImportPath = exports.selectBranchFromDirectory = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const path = tslib_1.__importStar(require("path"));
|
|
6
|
+
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
7
|
+
const file_helper_1 = require("./file-helper");
|
|
8
|
+
const interactive_1 = require("./interactive");
|
|
9
|
+
const config_1 = tslib_1.__importDefault(require("../config"));
|
|
10
|
+
/**
|
|
11
|
+
* Selects a branch from directory structure when multiple branches are found
|
|
12
|
+
* @param contentDir - The content directory path
|
|
13
|
+
* @returns Promise<{ branchPath: string } | null>
|
|
14
|
+
*/
|
|
15
|
+
const selectBranchFromDirectory = async (contentDir) => {
|
|
16
|
+
cli_utilities_1.log.debug('Selecting branch directory from directory structure');
|
|
17
|
+
const branchesJsonPath = path.join(contentDir, 'branches.json');
|
|
18
|
+
if (!(0, file_helper_1.fileExistsSync)(branchesJsonPath)) {
|
|
19
|
+
cli_utilities_1.log.debug('No branches.json found - not a branch-enabled export');
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const branchesData = await (0, file_helper_1.readFile)(branchesJsonPath);
|
|
24
|
+
const branches = branchesData || [];
|
|
25
|
+
if (!branches || !Array.isArray(branches) || branches.length === 0) {
|
|
26
|
+
cli_utilities_1.log.debug('No branches found in branches.json - not a branch-enabled export');
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
if (branches.length === 1) {
|
|
30
|
+
const singleBranch = branches[0];
|
|
31
|
+
const branchPath = path.join(contentDir, singleBranch.uid);
|
|
32
|
+
if (!(0, file_helper_1.fileExistsSync)(branchPath)) {
|
|
33
|
+
cli_utilities_1.log.warn(`Branch path does not exist: ${branchPath}, not a valid branch export`);
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
cli_utilities_1.log.debug(`Single branch detected: ${singleBranch.uid} - auto-resolving to: ${branchPath}`);
|
|
37
|
+
return { branchPath };
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
cli_utilities_1.log.debug(`Multiple branches detected: ${branches.map((b) => b.uid).join(', ')}`);
|
|
41
|
+
const branchNames = branches.map((b) => b.uid);
|
|
42
|
+
const selectedBranch = await (0, interactive_1.askBranchSelection)(branchNames);
|
|
43
|
+
const selectedBranchPath = path.join(contentDir, selectedBranch);
|
|
44
|
+
if (!(0, file_helper_1.fileExistsSync)(selectedBranchPath)) {
|
|
45
|
+
cli_utilities_1.log.warn(`Selected branch path does not exist: ${selectedBranchPath}, not a valid branch export`);
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
cli_utilities_1.log.debug(`User selected branch directory: ${selectedBranch} - using path: ${selectedBranchPath}`);
|
|
49
|
+
return { branchPath: selectedBranchPath };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
cli_utilities_1.log.error(`Error selecting branch directory from directory structure: ${error}`);
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
exports.selectBranchFromDirectory = selectBranchFromDirectory;
|
|
58
|
+
/**
|
|
59
|
+
* Resolves the import path based on directory structure and user configuration
|
|
60
|
+
* @param importConfig - The import configuration object
|
|
61
|
+
* @param stackAPIClient - The Contentstack API client
|
|
62
|
+
* @returns Promise<string> - The resolved path
|
|
63
|
+
*/
|
|
64
|
+
const resolveImportPath = async (importConfig, stackAPIClient) => {
|
|
65
|
+
cli_utilities_1.log.debug('Resolving import path based on directory structure');
|
|
66
|
+
const contentDir = importConfig.contentDir || importConfig.data;
|
|
67
|
+
cli_utilities_1.log.debug(`Content directory: ${contentDir}`);
|
|
68
|
+
if (!(0, file_helper_1.fileExistsSync)(contentDir)) {
|
|
69
|
+
throw new Error(`Content directory does not exist: ${contentDir}`);
|
|
70
|
+
}
|
|
71
|
+
if (importConfig.branchName) {
|
|
72
|
+
cli_utilities_1.log.debug(`User specified branch: ${importConfig.branchName}`);
|
|
73
|
+
const currentDirName = path.basename(contentDir);
|
|
74
|
+
if (currentDirName === importConfig.branchName) {
|
|
75
|
+
cli_utilities_1.log.debug(`Already in correct branch directory: ${contentDir}`);
|
|
76
|
+
return contentDir;
|
|
77
|
+
}
|
|
78
|
+
const branchPath = path.join(contentDir, importConfig.branchName);
|
|
79
|
+
if ((0, file_helper_1.fileExistsSync)(branchPath)) {
|
|
80
|
+
cli_utilities_1.log.debug(`Navigating to specified branch directory: ${branchPath}`);
|
|
81
|
+
return branchPath;
|
|
82
|
+
}
|
|
83
|
+
cli_utilities_1.log.debug(`Branch directory not found: ${branchPath}, using contentDir as-is`);
|
|
84
|
+
return contentDir;
|
|
85
|
+
}
|
|
86
|
+
const exportInfoPath = path.join(contentDir, 'export-info.json');
|
|
87
|
+
if ((0, file_helper_1.fileExistsSync)(exportInfoPath)) {
|
|
88
|
+
cli_utilities_1.log.debug('Found export-info.json - using contentDir as-is (v2 export)');
|
|
89
|
+
return contentDir;
|
|
90
|
+
}
|
|
91
|
+
const moduleTypes = config_1.default.modules.types;
|
|
92
|
+
const hasModuleFolders = moduleTypes.some((moduleType) => (0, file_helper_1.fileExistsSync)(path.join(contentDir, moduleType)));
|
|
93
|
+
if (hasModuleFolders) {
|
|
94
|
+
cli_utilities_1.log.debug('Found module folders ');
|
|
95
|
+
return contentDir;
|
|
96
|
+
}
|
|
97
|
+
const branchSelection = await (0, exports.selectBranchFromDirectory)(contentDir);
|
|
98
|
+
if (branchSelection) {
|
|
99
|
+
return branchSelection.branchPath;
|
|
100
|
+
}
|
|
101
|
+
cli_utilities_1.log.debug('No specific structure detected - using contentDir as-is');
|
|
102
|
+
return contentDir;
|
|
103
|
+
};
|
|
104
|
+
exports.resolveImportPath = resolveImportPath;
|
|
105
|
+
/**
|
|
106
|
+
* Updates the import configuration with the resolved path
|
|
107
|
+
* @param importConfig - The import configuration object
|
|
108
|
+
* @param resolvedPath - The resolved path
|
|
109
|
+
*/
|
|
110
|
+
const updateImportConfigWithResolvedPath = (importConfig, resolvedPath) => {
|
|
111
|
+
cli_utilities_1.log.debug(`Updating import config with resolved path: ${resolvedPath}`);
|
|
112
|
+
if (!(0, file_helper_1.fileExistsSync)(resolvedPath)) {
|
|
113
|
+
cli_utilities_1.log.warn(`Resolved path does not exist: ${resolvedPath}, skipping config update`);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
importConfig.branchDir = resolvedPath;
|
|
117
|
+
importConfig.contentDir = resolvedPath;
|
|
118
|
+
importConfig.data = resolvedPath;
|
|
119
|
+
cli_utilities_1.log.debug(`Import config updated - contentDir: ${importConfig.contentDir}, branchDir: ${importConfig.branchDir}, data: ${importConfig.data}`);
|
|
120
|
+
};
|
|
121
|
+
exports.updateImportConfigWithResolvedPath = updateImportConfigWithResolvedPath;
|
|
122
|
+
/**
|
|
123
|
+
* Executes the complete import path resolution logic
|
|
124
|
+
* @param importConfig - The import configuration object
|
|
125
|
+
* @param stackAPIClient - The Contentstack API client
|
|
126
|
+
* @returns Promise<string> - The resolved path
|
|
127
|
+
*/
|
|
128
|
+
const executeImportPathLogic = async (importConfig, stackAPIClient) => {
|
|
129
|
+
cli_utilities_1.log.debug('Executing import path resolution logic');
|
|
130
|
+
const resolvedPath = await (0, exports.resolveImportPath)(importConfig, stackAPIClient);
|
|
131
|
+
(0, exports.updateImportConfigWithResolvedPath)(importConfig, resolvedPath);
|
|
132
|
+
return resolvedPath;
|
|
133
|
+
};
|
|
134
|
+
exports.executeImportPathLogic = executeImportPathLogic;
|
package/lib/utils/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { setupBranchConfig } from './setup-branch';
|
|
2
|
+
export { selectBranchFromDirectory, resolveImportPath, updateImportConfigWithResolvedPath, executeImportPathLogic } from './import-path-resolver';
|
|
1
3
|
export * as interactive from './interactive';
|
|
2
4
|
export { default as setupImportConfig } from './import-config-handler';
|
|
3
5
|
export * as fileHelper from './file-helper';
|
package/lib/utils/index.js
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.lookUpTerms = exports.lookUpTaxonomy = exports.restoreJsonRteEntryRefs = exports.removeEntryRefsFromJSONRTE = exports.removeUidsFromJsonRteFields = exports.lookupEntries = exports.lookupExtension = exports.removeReferenceFields = exports.suppressSchemaReference = exports.schemaTemplate = exports.ifAppAlreadyExist = exports.getAllStackSpecificApps = exports.confirmToCloseProcess = exports.makeRedirectUrlCall = exports.handleNameConflict = 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.ifAppAlreadyExist = exports.getAllStackSpecificApps = exports.confirmToCloseProcess = exports.makeRedirectUrlCall = exports.handleNameConflict = exports.getConfirmationToCreateApps = exports.getOrgUid = exports.getDeveloperHubUrl = exports.lookupAssets = exports.uploadAssetHelper = exports.unlinkFileLogger = exports.log = exports.backupHandler = exports.fsUtil = exports.fileHelper = exports.setupImportConfig = exports.interactive = exports.executeImportPathLogic = exports.updateImportConfigWithResolvedPath = exports.resolveImportPath = exports.selectBranchFromDirectory = exports.setupBranchConfig = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
+
var setup_branch_1 = require("./setup-branch");
|
|
6
|
+
Object.defineProperty(exports, "setupBranchConfig", { enumerable: true, get: function () { return setup_branch_1.setupBranchConfig; } });
|
|
7
|
+
var import_path_resolver_1 = require("./import-path-resolver");
|
|
8
|
+
Object.defineProperty(exports, "selectBranchFromDirectory", { enumerable: true, get: function () { return import_path_resolver_1.selectBranchFromDirectory; } });
|
|
9
|
+
Object.defineProperty(exports, "resolveImportPath", { enumerable: true, get: function () { return import_path_resolver_1.resolveImportPath; } });
|
|
10
|
+
Object.defineProperty(exports, "updateImportConfigWithResolvedPath", { enumerable: true, get: function () { return import_path_resolver_1.updateImportConfigWithResolvedPath; } });
|
|
11
|
+
Object.defineProperty(exports, "executeImportPathLogic", { enumerable: true, get: function () { return import_path_resolver_1.executeImportPathLogic; } });
|
|
5
12
|
exports.interactive = tslib_1.__importStar(require("./interactive"));
|
|
6
13
|
var import_config_handler_1 = require("./import-config-handler");
|
|
7
14
|
Object.defineProperty(exports, "setupImportConfig", { enumerable: true, get: function () { return tslib_1.__importDefault(import_config_handler_1).default; } });
|
|
@@ -5,3 +5,4 @@ export declare const askAppName: (app: any, appSuffix: number) => Promise<string
|
|
|
5
5
|
export declare const getAppName: (name: string, appSuffix?: number) => string;
|
|
6
6
|
export declare const getLocationName: (name: string, appSuffix: number, existingNames: Set<string>) => string;
|
|
7
7
|
export declare const selectConfiguration: () => Promise<string>;
|
|
8
|
+
export declare const askBranchSelection: (branchNames: string[]) => Promise<string>;
|
package/lib/utils/interactive.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.selectConfiguration = exports.getLocationName = exports.getAppName = exports.askAppName = exports.askEncryptionKey = exports.askAPIKey = exports.askContentDir = void 0;
|
|
3
|
+
exports.askBranchSelection = exports.selectConfiguration = exports.getLocationName = exports.getAppName = exports.askAppName = exports.askEncryptionKey = exports.askAPIKey = exports.askContentDir = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
6
6
|
const path = tslib_1.__importStar(require("path"));
|
|
@@ -93,3 +93,12 @@ const selectConfiguration = async () => {
|
|
|
93
93
|
});
|
|
94
94
|
};
|
|
95
95
|
exports.selectConfiguration = selectConfiguration;
|
|
96
|
+
const askBranchSelection = async (branchNames) => {
|
|
97
|
+
return await cli_utilities_1.cliux.inquire({
|
|
98
|
+
type: 'list',
|
|
99
|
+
name: 'branch',
|
|
100
|
+
message: 'Found multiple branches in your export path. Please select one to import:',
|
|
101
|
+
choices: branchNames,
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
exports.askBranchSelection = askBranchSelection;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setupBranchConfig = void 0;
|
|
4
|
+
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
5
|
+
const common_helper_1 = require("./common-helper");
|
|
6
|
+
const setupBranchConfig = async (config, stackAPIClient) => {
|
|
7
|
+
if (config.branchName) {
|
|
8
|
+
await (0, common_helper_1.validateBranch)(stackAPIClient, config, config.branchName);
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (config.branchAlias) {
|
|
12
|
+
config.branchName = await (0, cli_utilities_1.getBranchFromAlias)(stackAPIClient, config.branchAlias);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const branches = await stackAPIClient
|
|
17
|
+
.branch()
|
|
18
|
+
.query()
|
|
19
|
+
.find()
|
|
20
|
+
.then(({ items }) => items);
|
|
21
|
+
if (branches.length) {
|
|
22
|
+
cli_utilities_1.log.info(`Stack is branch enabled and branches exist. Default import will be done in main branch.`);
|
|
23
|
+
config.branchName = 'main';
|
|
24
|
+
cli_utilities_1.log.debug(`Setting default target branch to 'main'`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
cli_utilities_1.log.debug('Failed to fetch branches', { error });
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
exports.setupBranchConfig = setupBranchConfig;
|
package/oclif.manifest.json
CHANGED
|
@@ -102,11 +102,24 @@
|
|
|
102
102
|
"branch": {
|
|
103
103
|
"char": "B",
|
|
104
104
|
"description": "The name of the branch where you want to import your content. If you don't mention the branch name, then by default the content will be imported to the main branch.",
|
|
105
|
+
"exclusive": [
|
|
106
|
+
"branch-alias"
|
|
107
|
+
],
|
|
105
108
|
"name": "branch",
|
|
106
109
|
"hasDynamicHelp": false,
|
|
107
110
|
"multiple": false,
|
|
108
111
|
"type": "option"
|
|
109
112
|
},
|
|
113
|
+
"branch-alias": {
|
|
114
|
+
"description": "The alias of the branch where you want to import your content. If you don't mention the branch alias, then by default the content will be imported to the main branch.",
|
|
115
|
+
"exclusive": [
|
|
116
|
+
"branch"
|
|
117
|
+
],
|
|
118
|
+
"name": "branch-alias",
|
|
119
|
+
"hasDynamicHelp": false,
|
|
120
|
+
"multiple": false,
|
|
121
|
+
"type": "option"
|
|
122
|
+
},
|
|
110
123
|
"import-webhook-status": {
|
|
111
124
|
"description": "[default: disable] (optional) This webhook state keeps the same state of webhooks as the source stack. <options: disable|current>",
|
|
112
125
|
"name": "import-webhook-status",
|
|
@@ -199,5 +212,5 @@
|
|
|
199
212
|
]
|
|
200
213
|
}
|
|
201
214
|
},
|
|
202
|
-
"version": "1.
|
|
215
|
+
"version": "1.28.0"
|
|
203
216
|
}
|
package/package.json
CHANGED
|
@@ -1,15 +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.
|
|
4
|
+
"version": "1.28.0",
|
|
5
5
|
"author": "Contentstack",
|
|
6
6
|
"bugs": "https://github.com/contentstack/cli/issues",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@contentstack/cli-audit": "~1.14.
|
|
9
|
-
"@contentstack/cli-command": "~1.6.
|
|
10
|
-
"@contentstack/cli-utilities": "~1.
|
|
8
|
+
"@contentstack/cli-audit": "~1.14.1",
|
|
9
|
+
"@contentstack/cli-command": "~1.6.1",
|
|
10
|
+
"@contentstack/cli-utilities": "~1.14.1",
|
|
11
11
|
"@contentstack/management": "~1.22.0",
|
|
12
|
-
"@contentstack/cli-variants": "~1.3.
|
|
12
|
+
"@contentstack/cli-variants": "~1.3.3",
|
|
13
13
|
"@oclif/core": "^4.3.0",
|
|
14
14
|
"big-json": "^3.2.0",
|
|
15
15
|
"bluebird": "^3.7.2",
|