-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathimport.ts
More file actions
235 lines (216 loc) · 9.59 KB
/
import.ts
File metadata and controls
235 lines (216 loc) · 9.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
import { Command } from '@contentstack/cli-command';
import {
messageHandler,
managementSDKClient,
flags,
FlagInput,
ContentstackClient,
log,
handleAndLogError,
configHandler,
getSessionLogPath,
CLIProgressManager,
cliux,
clearProgressModuleSetting,
createLogContext,
} from '@contentstack/cli-utilities';
import { Context, ImportConfig } from '../../../types';
import { ModuleImporter } from '../../../import';
import { setupImportConfig } from '../../../utils';
export default class ImportCommand extends Command {
static description = messageHandler.parse('Import content from a stack');
static examples: string[] = [
`csdx cm:stacks:import --stack-api-key <stack_api_key> --data-dir <path/of/export/destination/dir>`,
`csdx cm:stacks:import --config <path/of/config/dir>`,
`csdx cm:stacks:import --module <single module name>`,
`csdx cm:stacks:import --module <single module name> --backup-dir <backup dir>`,
`csdx cm:stacks:import --alias <management_token_alias>`,
`csdx cm:stacks:import --alias <management_token_alias> --data-dir <path/of/export/destination/dir>`,
`csdx cm:stacks:import --alias <management_token_alias> --config <path/of/config/file>`,
`csdx cm:stacks:import --branch <branch name> --yes --skip-audit`,
];
static flags: FlagInput = {
config: flags.string({
char: 'c',
description: '[optional] The path of the configuration JSON file containing all the options for a single run.',
}),
'stack-api-key': flags.string({
char: 'k',
description: 'API Key of the target stack',
}),
'data-dir': flags.string({
char: 'd',
description: `The path or the location in your file system where the content, you intend to import, is stored. For example, -d "C:\\Users\\Name\\Desktop\\cli\\content". If the export folder has branches involved, then the path should point till the particular branch. For example, “-d "C:\\Users\\Name\\Desktop\\cli\\content\\branch_name"`,
}),
alias: flags.string({
char: 'a',
description: 'The management token of the destination stack where you will import the content.',
}),
module: flags.string({
required: false,
description:
'[optional] Specify the module to import into the target stack. If not specified, the import command will import all the modules into the stack. The available modules are assets, content-types, entries, environments, extensions, marketplace-apps, global-fields, labels, locales, webhooks, workflows, custom-roles, personalize projects, taxonomies, and composable-studio.',
}),
'backup-dir': flags.string({
description: '[optional] Backup directory name when using specific module.',
}),
branch: flags.string({
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.",
exclusive: ['branch-alias'],
}),
'branch-alias': flags.string({
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.',
exclusive: ['branch'],
}),
'import-webhook-status': flags.string({
description:
'[default: disable] (optional) This webhook state keeps the same state of webhooks as the source stack. <options: disable|current>',
options: ['disable', 'current'],
required: false,
default: 'disable',
}),
yes: flags.boolean({
char: 'y',
required: false,
description: '[optional] Force override all Marketplace prompts.',
}),
'replace-existing': flags.boolean({
required: false,
description: 'Replaces the existing module in the target stack.',
}),
'skip-existing': flags.boolean({
required: false,
default: false,
description: 'Skips the module exists warning messages.',
}),
'personalize-project-name': flags.string({
required: false,
description: '(optional) Provide a unique name for the Personalize project.',
}),
'skip-audit': flags.boolean({
description: 'Skips the audit fix that occurs during an import operation.',
}),
'exclude-global-modules': flags.boolean({
description: 'Excludes the branch-independent module from the import operation.',
default: false,
}),
'skip-assets-publish': flags.boolean({
description: 'Skips asset publishing during the import process.',
default: false,
}),
'skip-entries-publish': flags.boolean({
description: 'Skips entry publishing during the import process',
default: false,
}),
'force-backup': flags.boolean({
description: 'Forces backup creation even for large datasets that would normally skip backup for memory optimization.',
default: false,
}),
'disable-memory-optimization': flags.boolean({
description: 'Disables memory optimization features and uses legacy processing (not recommended for large datasets).',
default: false,
}),
'memory-threshold': flags.integer({
description: 'Memory threshold in MB for triggering garbage collection (default: 768MB for large datasets).',
}),
'asset-concurrency': flags.integer({
description: 'Number of concurrent asset uploads (default: 10).',
}),
};
static usage: string =
'cm:stacks:import [--config <value>] [--stack-api-key <value>] [--data-dir <value>] [--alias <value>] [--module <value>] [--backup-dir <value>] [--branch <value>] [--import-webhook-status disable|current]';
async run(): Promise<void> {
// setup import config
// initialize the importer
// start import
let backupDir: string;
let importConfig: ImportConfig;
try {
const { flags } = await this.parse(ImportCommand);
importConfig = await setupImportConfig(flags);
// Prepare the context object
createLogContext(
this.context?.info?.command || 'cm:stacks:export',
importConfig.apiKey,
importConfig.authenticationMethod
);
const context = this.createImportContext(importConfig.apiKey, importConfig.authenticationMethod);
importConfig.context = { ...context };
//log.info(`Using Cli Version: ${this.context?.cliVersion}`, importConfig.context);
// Note setting host to create cma client
importConfig.host = this.cmaHost;
importConfig.region = this.region;
if (this.developerHubUrl) importConfig.developerHubBaseUrl = this.developerHubUrl;
if (this.personalizeUrl) importConfig.modules.personalize.baseURL[importConfig.region.name] = this.personalizeUrl;
if (this.composableStudioUrl) importConfig.modules['composable-studio'].apiBaseUrl = this.composableStudioUrl;
const managementAPIClient: ContentstackClient = await managementSDKClient(importConfig);
if (flags.branch) {
CLIProgressManager.initializeGlobalSummary(
`IMPORT-${flags.branch}`,
flags.branch,
`Importing content into "${flags.branch}" branch...`,
);
} else {
CLIProgressManager.initializeGlobalSummary(`IMPORT`, flags.branch, 'Importing content...');
}
const moduleImporter = new ModuleImporter(managementAPIClient, importConfig);
const result = await moduleImporter.start();
backupDir = importConfig.backupDir;
//Note: Final summary is now handled by summary manager
CLIProgressManager.printGlobalSummary();
this.logSuccessAndBackupMessages(backupDir, importConfig);
// Clear progress module setting now that import is complete
clearProgressModuleSetting();
} catch (error) {
// Clear progress module setting even on error
clearProgressModuleSetting();
handleAndLogError(error);
this.logAndPrintErrorDetails(error, importConfig);
}
}
private logAndPrintErrorDetails(error: unknown, importConfig: any) {
cliux.print('\n');
const sessionLogPath = getSessionLogPath();
const logMsg = `The log has been stored at '${sessionLogPath}'`;
const backupDir = importConfig?.backupDir;
const backupDirMsg = backupDir
? `The backup content has been stored at '${backupDir}'`
: 'No backup directory was created due to early termination';
log.info(logMsg);
log.info(backupDirMsg);
const showConsoleLogs = configHandler.get('log')?.showConsoleLogs;
if (!showConsoleLogs) {
cliux.print(`Error: ${error}`, { color: 'red' });
cliux.print(logMsg, { color: 'blue' });
cliux.print(backupDirMsg, { color: 'blue' });
}
}
private logSuccessAndBackupMessages(backupDir: string, importConfig: any) {
cliux.print('\n');
const sessionLogPath = getSessionLogPath();
const logMsg = `The log has been stored at '${sessionLogPath}'`;
const backupDirMsg = `The backup content has been stored at '${backupDir}'`;
log.success(logMsg, importConfig.context);
log.info(backupDirMsg, importConfig.context);
const showConsoleLogs = configHandler.get('log')?.showConsoleLogs;
if (!showConsoleLogs) {
cliux.print(logMsg, { color: 'blue' });
cliux.print(backupDirMsg, { color: 'blue' });
}
}
// Create export context object
private createImportContext(apiKey: string, authenticationMethod?: string): Context {
return {
command: this.context?.info?.command || 'cm:stacks:import',
module: '',
userId: configHandler.get('userUid') || '',
email: configHandler.get('email') || '',
sessionId: this.context?.sessionId,
apiKey: apiKey || '',
orgId: configHandler.get('oauthOrgUid') || '',
authenticationMethod: authenticationMethod || 'Basic Auth',
};
}
}