@contentstack/cli-cm-import 2.0.0-beta.1 → 2.0.0-beta.3
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 +125 -67
- package/lib/commands/cm/stacks/import.js +6 -3
- package/lib/config/index.js +7 -0
- package/lib/import/module-importer.js +9 -2
- package/lib/import/modules/base-class.d.ts +1 -0
- package/lib/import/modules/base-class.js +3 -1
- package/lib/import/modules/composable-studio.d.ts +43 -0
- package/lib/import/modules/composable-studio.js +227 -0
- package/lib/import/modules/stack.js +1 -1
- package/lib/import/modules/workflows.js +1 -1
- package/lib/types/default-config.d.ts +6 -0
- package/lib/types/import-config.d.ts +2 -0
- package/lib/types/index.d.ts +37 -11
- package/lib/utils/content-type-helper.js +2 -2
- package/lib/utils/file-helper.js +1 -1
- package/lib/utils/import-config-handler.js +2 -2
- package/lib/utils/import-path-resolver.js +24 -1
- package/lib/utils/login-handler.js +1 -1
- package/lib/utils/marketplace-app-helper.js +7 -4
- package/lib/utils/taxonomies-helper.js +1 -1
- package/messages/index.json +10 -1
- package/oclif.manifest.json +2 -2
- package/package.json +8 -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/2.0.0-beta.
|
|
50
|
+
@contentstack/cli-cm-import/2.0.0-beta.3 linux-x64 node-v22.21.1
|
|
51
51
|
$ csdx --help [COMMAND]
|
|
52
52
|
USAGE
|
|
53
53
|
$ csdx COMMAND
|
|
@@ -71,39 +71,68 @@ USAGE
|
|
|
71
71
|
[--backup-dir <value>] [--branch <value>] [--import-webhook-status disable|current]
|
|
72
72
|
|
|
73
73
|
FLAGS
|
|
74
|
-
-B, --branch=<value>
|
|
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
|
-
|
|
74
|
+
-B, --branch=<value>
|
|
75
|
+
The name of the branch where you want to import your content. If you don't mention the branch name, then by default
|
|
76
|
+
the content will be imported to the main branch.
|
|
77
|
+
|
|
78
|
+
-a, --alias=<value>
|
|
79
|
+
The management token of the destination stack where you will import the content.
|
|
80
|
+
|
|
81
|
+
-b, --backup-dir=<value>
|
|
82
|
+
[optional] Backup directory name when using specific module.
|
|
83
|
+
|
|
84
|
+
-c, --config=<value>
|
|
85
|
+
[optional] The path of the configuration JSON file containing all the options for a single run.
|
|
86
|
+
|
|
87
|
+
-d, --data-dir=<value>
|
|
88
|
+
The path or the location in your file system where the content, you intend to import, is stored. For example, -d
|
|
89
|
+
"C:\Users\Name\Desktop\cli\content". If the export folder has branches involved, then the path should point till the
|
|
90
|
+
particular branch. For example, “-d "C:\Users\Name\Desktop\cli\content\branch_name"
|
|
91
|
+
|
|
92
|
+
-k, --stack-api-key=<value>
|
|
93
|
+
API Key of the target stack
|
|
94
|
+
|
|
95
|
+
-m, --module=<value>
|
|
96
|
+
[optional] Specify the module to import into the target stack. If not specified, the import command will import all
|
|
97
|
+
the modules into the stack. The available modules are assets, content-types, entries, environments, extensions,
|
|
98
|
+
marketplace-apps, global-fields, labels, locales, webhooks, workflows, custom-roles, personalize projects,
|
|
99
|
+
taxonomies, and composable-studio.
|
|
100
|
+
|
|
101
|
+
-y, --yes
|
|
102
|
+
[optional] Force override all Marketplace prompts.
|
|
103
|
+
|
|
104
|
+
--branch-alias=<value>
|
|
105
|
+
Specify the branch alias where you want to import your content. If not specified, the content is imported into the
|
|
106
|
+
main branch by default.
|
|
107
|
+
|
|
108
|
+
--exclude-global-modules
|
|
109
|
+
Excludes the branch-independent module from the import operation.
|
|
110
|
+
|
|
111
|
+
--import-webhook-status=<option>
|
|
112
|
+
[default: disable] [default: disable] (optional) This webhook state keeps the same state of webhooks as the source
|
|
113
|
+
stack. <options: disable|current>
|
|
114
|
+
<options: disable|current>
|
|
115
|
+
|
|
116
|
+
--personalize-project-name=<value>
|
|
117
|
+
(optional) Provide a unique name for the Personalize project.
|
|
118
|
+
|
|
119
|
+
--replace-existing
|
|
120
|
+
Replaces the existing module in the target stack.
|
|
121
|
+
|
|
122
|
+
--skip-app-recreation
|
|
123
|
+
(optional) Skips the recreation of private apps if they already exist.
|
|
124
|
+
|
|
125
|
+
--skip-assets-publish
|
|
126
|
+
Skips asset publishing during the import process.
|
|
127
|
+
|
|
128
|
+
--skip-audit
|
|
129
|
+
Skips the audit fix that occurs during an import operation.
|
|
130
|
+
|
|
131
|
+
--skip-entries-publish
|
|
132
|
+
Skips entry publishing during the import process
|
|
133
|
+
|
|
134
|
+
--skip-existing
|
|
135
|
+
Skips the module exists warning messages.
|
|
107
136
|
|
|
108
137
|
DESCRIPTION
|
|
109
138
|
Import content from a stack
|
|
@@ -139,39 +168,68 @@ USAGE
|
|
|
139
168
|
<value>] [--branch <value>] [--import-webhook-status disable|current]
|
|
140
169
|
|
|
141
170
|
FLAGS
|
|
142
|
-
-B, --branch=<value>
|
|
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
|
-
|
|
171
|
+
-B, --branch=<value>
|
|
172
|
+
The name of the branch where you want to import your content. If you don't mention the branch name, then by default
|
|
173
|
+
the content will be imported to the main branch.
|
|
174
|
+
|
|
175
|
+
-a, --alias=<value>
|
|
176
|
+
The management token of the destination stack where you will import the content.
|
|
177
|
+
|
|
178
|
+
-b, --backup-dir=<value>
|
|
179
|
+
[optional] Backup directory name when using specific module.
|
|
180
|
+
|
|
181
|
+
-c, --config=<value>
|
|
182
|
+
[optional] The path of the configuration JSON file containing all the options for a single run.
|
|
183
|
+
|
|
184
|
+
-d, --data-dir=<value>
|
|
185
|
+
The path or the location in your file system where the content, you intend to import, is stored. For example, -d
|
|
186
|
+
"C:\Users\Name\Desktop\cli\content". If the export folder has branches involved, then the path should point till the
|
|
187
|
+
particular branch. For example, “-d "C:\Users\Name\Desktop\cli\content\branch_name"
|
|
188
|
+
|
|
189
|
+
-k, --stack-api-key=<value>
|
|
190
|
+
API Key of the target stack
|
|
191
|
+
|
|
192
|
+
-m, --module=<value>
|
|
193
|
+
[optional] Specify the module to import into the target stack. If not specified, the import command will import all
|
|
194
|
+
the modules into the stack. The available modules are assets, content-types, entries, environments, extensions,
|
|
195
|
+
marketplace-apps, global-fields, labels, locales, webhooks, workflows, custom-roles, personalize projects,
|
|
196
|
+
taxonomies, and composable-studio.
|
|
197
|
+
|
|
198
|
+
-y, --yes
|
|
199
|
+
[optional] Force override all Marketplace prompts.
|
|
200
|
+
|
|
201
|
+
--branch-alias=<value>
|
|
202
|
+
Specify the branch alias where you want to import your content. If not specified, the content is imported into the
|
|
203
|
+
main branch by default.
|
|
204
|
+
|
|
205
|
+
--exclude-global-modules
|
|
206
|
+
Excludes the branch-independent module from the import operation.
|
|
207
|
+
|
|
208
|
+
--import-webhook-status=<option>
|
|
209
|
+
[default: disable] [default: disable] (optional) This webhook state keeps the same state of webhooks as the source
|
|
210
|
+
stack. <options: disable|current>
|
|
211
|
+
<options: disable|current>
|
|
212
|
+
|
|
213
|
+
--personalize-project-name=<value>
|
|
214
|
+
(optional) Provide a unique name for the Personalize project.
|
|
215
|
+
|
|
216
|
+
--replace-existing
|
|
217
|
+
Replaces the existing module in the target stack.
|
|
218
|
+
|
|
219
|
+
--skip-app-recreation
|
|
220
|
+
(optional) Skips the recreation of private apps if they already exist.
|
|
221
|
+
|
|
222
|
+
--skip-assets-publish
|
|
223
|
+
Skips asset publishing during the import process.
|
|
224
|
+
|
|
225
|
+
--skip-audit
|
|
226
|
+
Skips the audit fix that occurs during an import operation.
|
|
227
|
+
|
|
228
|
+
--skip-entries-publish
|
|
229
|
+
Skips entry publishing during the import process
|
|
230
|
+
|
|
231
|
+
--skip-existing
|
|
232
|
+
Skips the module exists warning messages.
|
|
175
233
|
|
|
176
234
|
DESCRIPTION
|
|
177
235
|
Import content from a stack
|
|
@@ -17,7 +17,7 @@ class ImportCommand extends cli_command_1.Command {
|
|
|
17
17
|
// Prepare the context object
|
|
18
18
|
const context = this.createImportContext(importConfig.apiKey, importConfig.authenticationMethod);
|
|
19
19
|
importConfig.context = Object.assign({}, context);
|
|
20
|
-
//log.info(`Using
|
|
20
|
+
// log.info(`Using CLI version: ${this.context?.cliVersion}`, importConfig.context);
|
|
21
21
|
// Note setting host to create cma client
|
|
22
22
|
importConfig.host = this.cmaHost;
|
|
23
23
|
importConfig.region = this.region;
|
|
@@ -25,6 +25,8 @@ class ImportCommand extends cli_command_1.Command {
|
|
|
25
25
|
importConfig.developerHubBaseUrl = this.developerHubUrl;
|
|
26
26
|
if (this.personalizeUrl)
|
|
27
27
|
importConfig.modules.personalize.baseURL[importConfig.region.name] = this.personalizeUrl;
|
|
28
|
+
if (this.composableStudioUrl)
|
|
29
|
+
importConfig.modules['composable-studio'].apiBaseUrl = this.composableStudioUrl;
|
|
28
30
|
const managementAPIClient = await (0, cli_utilities_1.managementSDKClient)(importConfig);
|
|
29
31
|
if (flags.branch) {
|
|
30
32
|
cli_utilities_1.CLIProgressManager.initializeGlobalSummary(`IMPORT-${flags.branch}`, flags.branch, `Importing content into "${flags.branch}" branch...`);
|
|
@@ -92,6 +94,7 @@ class ImportCommand extends cli_command_1.Command {
|
|
|
92
94
|
command: ((_b = (_a = this.context) === null || _a === void 0 ? void 0 : _a.info) === null || _b === void 0 ? void 0 : _b.command) || 'cm:stacks:import',
|
|
93
95
|
module: '',
|
|
94
96
|
userId: cli_utilities_1.configHandler.get('userUid') || '',
|
|
97
|
+
email: cli_utilities_1.configHandler.get('email') || '',
|
|
95
98
|
sessionId: (_c = this.context) === null || _c === void 0 ? void 0 : _c.sessionId,
|
|
96
99
|
apiKey: apiKey || '',
|
|
97
100
|
orgId: cli_utilities_1.configHandler.get('oauthOrgUid') || '',
|
|
@@ -153,7 +156,7 @@ ImportCommand.flags = {
|
|
|
153
156
|
module: cli_utilities_1.flags.string({
|
|
154
157
|
required: false,
|
|
155
158
|
char: 'm',
|
|
156
|
-
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, and
|
|
159
|
+
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.',
|
|
157
160
|
parse: (0, cli_utilities_1.printFlagDeprecation)(['-m'], ['--module']),
|
|
158
161
|
}),
|
|
159
162
|
'backup-dir': cli_utilities_1.flags.string({
|
|
@@ -168,7 +171,7 @@ ImportCommand.flags = {
|
|
|
168
171
|
exclusive: ['branch-alias'],
|
|
169
172
|
}),
|
|
170
173
|
'branch-alias': cli_utilities_1.flags.string({
|
|
171
|
-
description:
|
|
174
|
+
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.',
|
|
172
175
|
exclusive: ['branch'],
|
|
173
176
|
}),
|
|
174
177
|
'import-webhook-status': cli_utilities_1.flags.string({
|
package/lib/config/index.js
CHANGED
|
@@ -44,6 +44,7 @@ const config = {
|
|
|
44
44
|
'variant-entries',
|
|
45
45
|
'labels',
|
|
46
46
|
'webhooks',
|
|
47
|
+
'composable-studio',
|
|
47
48
|
],
|
|
48
49
|
locales: {
|
|
49
50
|
dirName: 'locales',
|
|
@@ -199,6 +200,12 @@ const config = {
|
|
|
199
200
|
locale: 'en-us',
|
|
200
201
|
},
|
|
201
202
|
},
|
|
203
|
+
'composable-studio': {
|
|
204
|
+
dirName: 'composable_studio',
|
|
205
|
+
fileName: 'composable_studio.json',
|
|
206
|
+
apiBaseUrl: 'https://composable-studio-api.contentstack.com',
|
|
207
|
+
apiVersion: 'v1',
|
|
208
|
+
},
|
|
202
209
|
},
|
|
203
210
|
languagesCode: [
|
|
204
211
|
'af-za',
|
|
@@ -66,8 +66,15 @@ class ModuleImporter {
|
|
|
66
66
|
}
|
|
67
67
|
async importByModuleByName(moduleName) {
|
|
68
68
|
cli_utilities_1.log.info(`Starting import of ${moduleName} module`, this.importConfig.context);
|
|
69
|
-
//
|
|
70
|
-
|
|
69
|
+
// Check if module should be skipped for legacy contentVersion
|
|
70
|
+
if (this.importConfig.contentVersion !== 2) {
|
|
71
|
+
const onlyTSModules = this.importConfig.onlyTSModules || [];
|
|
72
|
+
if (onlyTSModules.includes(moduleName)) {
|
|
73
|
+
// Module is in onlyTSModules list, skip import for legacy contentVersion
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Use module import (same for both contentVersion 1 and 2)
|
|
71
78
|
return (0, modules_1.default)({
|
|
72
79
|
stackAPIClient: this.stackAPIClient,
|
|
73
80
|
importConfig: this.importConfig,
|
|
@@ -10,6 +10,7 @@ export type ApiOptions = {
|
|
|
10
10
|
url?: string;
|
|
11
11
|
entity: ApiModuleType;
|
|
12
12
|
apiData?: Record<any, any> | any;
|
|
13
|
+
queryParam?: Record<any, any>;
|
|
13
14
|
resolve: (value: any) => Promise<void> | void;
|
|
14
15
|
reject: (error: any) => Promise<void> | void;
|
|
15
16
|
additionalInfo?: Record<any, any>;
|
|
@@ -337,7 +337,9 @@ class BaseClass {
|
|
|
337
337
|
if (!apiData || !apiData.filePath) {
|
|
338
338
|
return Promise.resolve();
|
|
339
339
|
}
|
|
340
|
-
|
|
340
|
+
const importParams = { taxonomy: apiData.filePath };
|
|
341
|
+
const importQueryParam = apiOptions.queryParam || {};
|
|
342
|
+
return this.stack.taxonomy(uid).import(importParams, importQueryParam).then(onSuccess).catch(onReject);
|
|
341
343
|
default:
|
|
342
344
|
return Promise.resolve();
|
|
343
345
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ModuleClassParams, ComposableStudioProject } from '../../types';
|
|
2
|
+
export default class ImportComposableStudio {
|
|
3
|
+
private importConfig;
|
|
4
|
+
private composableStudioConfig;
|
|
5
|
+
private composableStudioPath;
|
|
6
|
+
private composableStudioFilePath;
|
|
7
|
+
private apiClient;
|
|
8
|
+
private envUidMapperPath;
|
|
9
|
+
private envUidMapper;
|
|
10
|
+
constructor({ importConfig }: ModuleClassParams);
|
|
11
|
+
/**
|
|
12
|
+
* Entry point for Studio import
|
|
13
|
+
*/
|
|
14
|
+
start(): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Initialize authentication headers for API calls
|
|
17
|
+
*/
|
|
18
|
+
addAuthHeaders(): Promise<boolean>;
|
|
19
|
+
/**
|
|
20
|
+
* Load environment UID mapper from backup directory
|
|
21
|
+
*/
|
|
22
|
+
loadEnvironmentMapper(): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Read exported project from file system
|
|
25
|
+
*/
|
|
26
|
+
readExportedProject(): Promise<ComposableStudioProject | null>;
|
|
27
|
+
/**
|
|
28
|
+
* Check if target stack already has a connected project
|
|
29
|
+
*/
|
|
30
|
+
getExistingProject(): Promise<ComposableStudioProject | null>;
|
|
31
|
+
/**
|
|
32
|
+
* Import project with name conflict handling
|
|
33
|
+
*/
|
|
34
|
+
importProject(exportedProject: ComposableStudioProject): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Map environment UID from source to target
|
|
37
|
+
*/
|
|
38
|
+
mapEnvironmentUid(sourceEnvUid: string): string;
|
|
39
|
+
/**
|
|
40
|
+
* Prompt user for a new project name when conflict occurs
|
|
41
|
+
*/
|
|
42
|
+
promptForNewProjectName(currentName: string): Promise<string>;
|
|
43
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const node_path_1 = require("node:path");
|
|
5
|
+
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
6
|
+
const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
|
|
7
|
+
const utils_1 = require("../../utils");
|
|
8
|
+
class ImportComposableStudio {
|
|
9
|
+
constructor({ importConfig }) {
|
|
10
|
+
this.importConfig = importConfig;
|
|
11
|
+
this.importConfig.context.module = 'composable-studio';
|
|
12
|
+
this.composableStudioConfig = importConfig.modules['composable-studio'];
|
|
13
|
+
// Setup paths
|
|
14
|
+
this.composableStudioPath = (0, node_path_1.join)(this.importConfig.backupDir, this.composableStudioConfig.dirName);
|
|
15
|
+
this.composableStudioFilePath = (0, node_path_1.join)(this.composableStudioPath, this.composableStudioConfig.fileName);
|
|
16
|
+
this.envUidMapperPath = (0, node_path_1.join)(this.importConfig.backupDir, 'mapper', 'environments', 'uid-mapping.json');
|
|
17
|
+
this.envUidMapper = {};
|
|
18
|
+
// Initialize HttpClient with Studio API base URL
|
|
19
|
+
this.apiClient = new cli_utilities_1.HttpClient();
|
|
20
|
+
this.apiClient.baseUrl(`${this.composableStudioConfig.apiBaseUrl}/${this.composableStudioConfig.apiVersion}`);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Entry point for Studio import
|
|
24
|
+
*/
|
|
25
|
+
async start() {
|
|
26
|
+
if (this.importConfig.management_token) {
|
|
27
|
+
cli_utilities_1.log.warn('Skipping Studio project import when using management token', this.importConfig.context);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
cli_utilities_1.log.debug('Starting Studio project import process...', this.importConfig.context);
|
|
31
|
+
try {
|
|
32
|
+
// Initialize authentication
|
|
33
|
+
const authInitialized = await this.addAuthHeaders();
|
|
34
|
+
if (!authInitialized) {
|
|
35
|
+
cli_utilities_1.log.warn('Skipping Studio project import when using OAuth authentication', this.importConfig.context);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// Load environment UID mapper
|
|
39
|
+
await this.loadEnvironmentMapper();
|
|
40
|
+
// Read exported project data
|
|
41
|
+
const exportedProject = await this.readExportedProject();
|
|
42
|
+
if (!exportedProject) {
|
|
43
|
+
cli_utilities_1.log.warn(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_NOT_FOUND'), this.importConfig.context);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
cli_utilities_1.log.debug(`Exported project found: ${exportedProject.name}`, this.importConfig.context);
|
|
47
|
+
// Check if target stack already has a connected project
|
|
48
|
+
const existingProject = await this.getExistingProject();
|
|
49
|
+
if (existingProject) {
|
|
50
|
+
cli_utilities_1.log.warn(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_SKIP_EXISTING'), this.importConfig.context);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
// Import the project with name conflict handling
|
|
54
|
+
await this.importProject(exportedProject);
|
|
55
|
+
cli_utilities_1.log.success(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_IMPORT_COMPLETE', exportedProject.name), this.importConfig.context);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
(0, cli_utilities_1.handleAndLogError)(error, Object.assign({}, this.importConfig.context));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Initialize authentication headers for API calls
|
|
63
|
+
*/
|
|
64
|
+
async addAuthHeaders() {
|
|
65
|
+
cli_utilities_1.log.debug('Initializing Studio API authentication...', this.importConfig.context);
|
|
66
|
+
// Get authentication details - following personalization-api-adapter pattern
|
|
67
|
+
await cli_utilities_1.authenticationHandler.getAuthDetails();
|
|
68
|
+
const token = cli_utilities_1.authenticationHandler.accessToken;
|
|
69
|
+
cli_utilities_1.log.debug(`Authentication type: ${cli_utilities_1.authenticationHandler.isOauthEnabled ? 'OAuth' : 'Token'}`, this.importConfig.context);
|
|
70
|
+
// Set authentication headers based on auth type
|
|
71
|
+
if (cli_utilities_1.authenticationHandler.isOauthEnabled) {
|
|
72
|
+
cli_utilities_1.log.debug('Skipping setting OAuth authorization header when using OAuth authentication', this.importConfig.context);
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
// TODO: Currenlty assuming if auth type is not OAuth, it is Basic Auth and we are setting authtoken header
|
|
77
|
+
cli_utilities_1.log.debug('Setting authtoken header', this.importConfig.context);
|
|
78
|
+
this.apiClient.headers({ authtoken: token });
|
|
79
|
+
}
|
|
80
|
+
// Set organization_uid header
|
|
81
|
+
this.apiClient.headers({
|
|
82
|
+
organization_uid: this.importConfig.org_uid,
|
|
83
|
+
'Content-Type': 'application/json',
|
|
84
|
+
Accept: 'application/json',
|
|
85
|
+
});
|
|
86
|
+
cli_utilities_1.log.debug('Studio API authentication initialized', this.importConfig.context);
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Load environment UID mapper from backup directory
|
|
91
|
+
*/
|
|
92
|
+
async loadEnvironmentMapper() {
|
|
93
|
+
cli_utilities_1.log.debug('Loading environment UID mapper...', this.importConfig.context);
|
|
94
|
+
if (utils_1.fileHelper.fileExistsSync(this.envUidMapperPath)) {
|
|
95
|
+
this.envUidMapper = utils_1.fileHelper.readFileSync(this.envUidMapperPath);
|
|
96
|
+
cli_utilities_1.log.debug(`Environment mapper loaded with ${Object.keys(this.envUidMapper).length} mappings`, this.importConfig.context);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
cli_utilities_1.log.debug('No environment UID mapper found', this.importConfig.context);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Read exported project from file system
|
|
104
|
+
*/
|
|
105
|
+
async readExportedProject() {
|
|
106
|
+
cli_utilities_1.log.debug(`Reading exported project from: ${this.composableStudioFilePath}`, this.importConfig.context);
|
|
107
|
+
if (!utils_1.fileHelper.fileExistsSync(this.composableStudioFilePath)) {
|
|
108
|
+
cli_utilities_1.log.debug('Studio project file does not exist', this.importConfig.context);
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
const projectData = utils_1.fileHelper.readFileSync(this.composableStudioFilePath);
|
|
112
|
+
if (!projectData || (0, isEmpty_1.default)(projectData)) {
|
|
113
|
+
cli_utilities_1.log.debug('Studio project file is empty', this.importConfig.context);
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
return projectData;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Check if target stack already has a connected project
|
|
120
|
+
*/
|
|
121
|
+
async getExistingProject() {
|
|
122
|
+
var _a;
|
|
123
|
+
cli_utilities_1.log.debug('Checking if target stack already has a connected project...', this.importConfig.context);
|
|
124
|
+
try {
|
|
125
|
+
const apiUrl = '/projects';
|
|
126
|
+
cli_utilities_1.log.debug(`Fetching projects from: ${this.composableStudioConfig.apiBaseUrl}${apiUrl}`, this.importConfig.context);
|
|
127
|
+
const response = await this.apiClient.get(apiUrl);
|
|
128
|
+
if (response.status < 200 || response.status >= 300) {
|
|
129
|
+
throw new Error(`API call failed with status ${response.status}: ${JSON.stringify(response.data)}`);
|
|
130
|
+
}
|
|
131
|
+
const projects = ((_a = response.data) === null || _a === void 0 ? void 0 : _a.projects) || [];
|
|
132
|
+
cli_utilities_1.log.debug(`Found ${projects.length} projects in organization`, this.importConfig.context);
|
|
133
|
+
// Filter projects by connected stack API key
|
|
134
|
+
const connectedProject = projects.find((project) => project.connectedStackApiKey === this.importConfig.apiKey);
|
|
135
|
+
if (connectedProject) {
|
|
136
|
+
cli_utilities_1.log.debug(`Target stack already has connected project: ${connectedProject.name}`, this.importConfig.context);
|
|
137
|
+
return connectedProject;
|
|
138
|
+
}
|
|
139
|
+
cli_utilities_1.log.debug('Target stack does not have a connected project', this.importConfig.context);
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
cli_utilities_1.log.debug(`Error checking for existing project: ${error.message}`, this.importConfig.context);
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Import project with name conflict handling
|
|
149
|
+
*/
|
|
150
|
+
async importProject(exportedProject) {
|
|
151
|
+
var _a, _b, _c;
|
|
152
|
+
cli_utilities_1.log.debug('Starting project import...', this.importConfig.context);
|
|
153
|
+
// Map environment UID
|
|
154
|
+
const mappedEnvironmentUid = this.mapEnvironmentUid(exportedProject.settings.configuration.environment);
|
|
155
|
+
// Prepare project data for import
|
|
156
|
+
const projectData = {
|
|
157
|
+
name: exportedProject.name,
|
|
158
|
+
connectedStackApiKey: this.importConfig.apiKey,
|
|
159
|
+
contentTypeUid: exportedProject.contentTypeUid,
|
|
160
|
+
description: exportedProject.description || '',
|
|
161
|
+
canvasUrl: exportedProject.canvasUrl || '/',
|
|
162
|
+
settings: {
|
|
163
|
+
configuration: {
|
|
164
|
+
environment: mappedEnvironmentUid,
|
|
165
|
+
locale: ((_b = (_a = exportedProject === null || exportedProject === void 0 ? void 0 : exportedProject.settings) === null || _a === void 0 ? void 0 : _a.configuration) === null || _b === void 0 ? void 0 : _b.locale) || '',
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
cli_utilities_1.log.debug(`Project data prepared: ${JSON.stringify(projectData, null, 2)}`, this.importConfig.context);
|
|
170
|
+
// Try to create project with name conflict retry loop
|
|
171
|
+
let projectCreated = false;
|
|
172
|
+
let currentName = projectData.name;
|
|
173
|
+
let attemptCount = 0;
|
|
174
|
+
while (!projectCreated) {
|
|
175
|
+
attemptCount++;
|
|
176
|
+
cli_utilities_1.log.debug(`Attempt ${attemptCount} to create project with name: ${currentName}`, this.importConfig.context);
|
|
177
|
+
projectData.name = currentName;
|
|
178
|
+
const response = await this.apiClient.post('/projects', projectData);
|
|
179
|
+
if (response.status >= 200 && response.status < 300) {
|
|
180
|
+
projectCreated = true;
|
|
181
|
+
cli_utilities_1.log.debug(`Project created successfully with UID: ${(_c = response.data) === null || _c === void 0 ? void 0 : _c.uid}`, this.importConfig.context);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
throw new Error(`API call failed with status ${response.status}: ${JSON.stringify(response.data)}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Map environment UID from source to target
|
|
190
|
+
*/
|
|
191
|
+
mapEnvironmentUid(sourceEnvUid) {
|
|
192
|
+
if (!sourceEnvUid) {
|
|
193
|
+
cli_utilities_1.log.debug('Source environment UID is empty', this.importConfig.context);
|
|
194
|
+
return '';
|
|
195
|
+
}
|
|
196
|
+
cli_utilities_1.log.debug(`Mapping source environment UID: ${sourceEnvUid}`, this.importConfig.context);
|
|
197
|
+
if ((0, isEmpty_1.default)(this.envUidMapper)) {
|
|
198
|
+
cli_utilities_1.log.warn(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_ENV_MAPPING_FAILED', sourceEnvUid), this.importConfig.context);
|
|
199
|
+
return '';
|
|
200
|
+
}
|
|
201
|
+
const mappedUid = this.envUidMapper[sourceEnvUid];
|
|
202
|
+
if (!mappedUid) {
|
|
203
|
+
cli_utilities_1.log.warn(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_ENV_MAPPING_FAILED', sourceEnvUid), this.importConfig.context);
|
|
204
|
+
return '';
|
|
205
|
+
}
|
|
206
|
+
cli_utilities_1.log.debug(`Mapped environment UID: ${sourceEnvUid} → ${mappedUid}`, this.importConfig.context);
|
|
207
|
+
return mappedUid;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Prompt user for a new project name when conflict occurs
|
|
211
|
+
*/
|
|
212
|
+
async promptForNewProjectName(currentName) {
|
|
213
|
+
const suggestedName = `Copy of ${currentName}`;
|
|
214
|
+
cli_utilities_1.log.warn(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_NAME_CONFLICT', currentName), this.importConfig.context);
|
|
215
|
+
cli_utilities_1.log.info(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_SUGGEST_NAME', suggestedName), this.importConfig.context);
|
|
216
|
+
const response = await cli_utilities_1.cliux.inquire({
|
|
217
|
+
type: 'input',
|
|
218
|
+
name: 'projectName',
|
|
219
|
+
message: 'Enter new project name:',
|
|
220
|
+
default: suggestedName,
|
|
221
|
+
});
|
|
222
|
+
const newName = response.projectName || suggestedName;
|
|
223
|
+
cli_utilities_1.log.debug(`User provided new project name: ${newName}`, this.importConfig.context);
|
|
224
|
+
return newName;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
exports.default = ImportComposableStudio;
|
|
@@ -47,7 +47,7 @@ class ImportStack extends base_class_1.default {
|
|
|
47
47
|
var _a, _b, _c;
|
|
48
48
|
cli_utilities_1.log.debug('Processing stack settings for import', this.importConfig.context);
|
|
49
49
|
// Update environment UID mapping if live preview is configured
|
|
50
|
-
if (((_a = this.stackSettings) === null || _a === void 0 ? void 0 : _a.live_preview) && ((_b = this.stackSettings) === null || _b === void 0 ? void 0 : _b.live_preview['default-env'])) {
|
|
50
|
+
if (((_a = this.stackSettings) === null || _a === void 0 ? void 0 : _a.live_preview) && ((_b = this.stackSettings) === null || _b === void 0 ? void 0 : _b.live_preview['default-env']) !== undefined) {
|
|
51
51
|
const oldEnvUid = this.stackSettings.live_preview['default-env'];
|
|
52
52
|
const mappedEnvUid = this.envUidMapper[oldEnvUid];
|
|
53
53
|
if (mappedEnvUid) {
|
|
@@ -142,7 +142,7 @@ class ImportWorkflows extends base_class_1.default {
|
|
|
142
142
|
else {
|
|
143
143
|
this.failedWebhooks.push(apiData);
|
|
144
144
|
(_d = this.progressManager) === null || _d === void 0 ? void 0 : _d.tick(false, `workflow: ${name || uid}`, (error === null || error === void 0 ? void 0 : error.message) || 'Failed to import workflow', utils_1.PROCESS_NAMES.WORKFLOWS_CREATE);
|
|
145
|
-
if (error.errors['workflow_stages.0.users']) {
|
|
145
|
+
if ((error === null || error === void 0 ? void 0 : error.errors) && error.errors['workflow_stages.0.users']) {
|
|
146
146
|
cli_utilities_1.log.error("Failed to import Workflows as you've specified certain roles in the Stage transition and access rules section. We currently don't import roles to the stack.", this.importConfig.context);
|
|
147
147
|
}
|
|
148
148
|
else {
|
|
@@ -156,6 +156,12 @@ export default interface DefaultConfig {
|
|
|
156
156
|
locale: string;
|
|
157
157
|
} & AnyProperty;
|
|
158
158
|
} & AnyProperty;
|
|
159
|
+
'composable-studio': {
|
|
160
|
+
dirName: string;
|
|
161
|
+
fileName: string;
|
|
162
|
+
apiBaseUrl: string;
|
|
163
|
+
apiVersion: string;
|
|
164
|
+
};
|
|
159
165
|
};
|
|
160
166
|
languagesCode: string[];
|
|
161
167
|
apis: {
|
|
@@ -48,6 +48,7 @@ export default interface ImportConfig extends DefaultConfig, ExternalConfig {
|
|
|
48
48
|
authtoken?: string;
|
|
49
49
|
destinationStackName?: string;
|
|
50
50
|
org_uid?: string;
|
|
51
|
+
contentVersion: number;
|
|
51
52
|
replaceExisting?: boolean;
|
|
52
53
|
skipExisting?: boolean;
|
|
53
54
|
skipAudit?: boolean;
|
|
@@ -56,6 +57,7 @@ export default interface ImportConfig extends DefaultConfig, ExternalConfig {
|
|
|
56
57
|
personalizeProjectName?: string;
|
|
57
58
|
'exclude-global-modules': false;
|
|
58
59
|
context: Context;
|
|
60
|
+
onlyTSModules?: Modules[];
|
|
59
61
|
}
|
|
60
62
|
type branch = {
|
|
61
63
|
uid: string;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ export interface User {
|
|
|
26
26
|
email: string;
|
|
27
27
|
authtoken: string;
|
|
28
28
|
}
|
|
29
|
-
export type Modules = 'stack' | 'assets' | 'locales' | 'environments' | 'extensions' | 'webhooks' | 'global-fields' | 'entries' | 'content-types' | 'custom-roles' | 'workflows' | 'labels' | 'marketplace-apps' | 'taxonomies' | 'personalize' | 'variant-entries';
|
|
29
|
+
export type Modules = 'stack' | 'assets' | 'locales' | 'environments' | 'extensions' | 'webhooks' | 'global-fields' | 'entries' | 'content-types' | 'custom-roles' | 'workflows' | 'labels' | 'marketplace-apps' | 'taxonomies' | 'personalize' | 'variant-entries' | 'composable-studio';
|
|
30
30
|
export type ModuleClassParams = {
|
|
31
31
|
stackAPIClient: ReturnType<ContentstackClient['stack']>;
|
|
32
32
|
importConfig: ImportConfig;
|
|
@@ -71,23 +71,49 @@ export interface TaxonomiesConfig {
|
|
|
71
71
|
fileName: string;
|
|
72
72
|
dependencies?: Modules[];
|
|
73
73
|
}
|
|
74
|
-
export
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
74
|
+
export interface ComposableStudioConfig {
|
|
75
|
+
dirName: string;
|
|
76
|
+
fileName: string;
|
|
77
|
+
apiBaseUrl: string;
|
|
78
|
+
apiVersion: string;
|
|
79
|
+
}
|
|
80
|
+
export interface ComposableStudioProject {
|
|
81
|
+
name: string;
|
|
82
|
+
description: string;
|
|
83
|
+
canvasUrl: string;
|
|
84
|
+
connectedStackApiKey: string;
|
|
85
|
+
contentTypeUid: string;
|
|
86
|
+
organizationUid: string;
|
|
87
|
+
settings: {
|
|
88
|
+
configuration: {
|
|
89
|
+
environment: string;
|
|
90
|
+
locale: string;
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
uid?: string;
|
|
94
|
+
createdBy?: string;
|
|
95
|
+
updatedBy?: string;
|
|
96
|
+
deletedAt?: boolean;
|
|
97
|
+
createdAt?: string;
|
|
98
|
+
updatedAt?: string;
|
|
99
|
+
}
|
|
83
100
|
export interface Context {
|
|
84
101
|
command: string;
|
|
85
102
|
module: string;
|
|
86
103
|
userId: string | undefined;
|
|
87
|
-
email
|
|
104
|
+
email: string | undefined;
|
|
88
105
|
sessionId: string | undefined;
|
|
89
106
|
clientId?: string | undefined;
|
|
90
107
|
apiKey: string;
|
|
91
108
|
orgId: string;
|
|
92
109
|
authenticationMethod?: string;
|
|
93
110
|
}
|
|
111
|
+
export { default as DefaultConfig } from './default-config';
|
|
112
|
+
export { default as ImportConfig } from './import-config';
|
|
113
|
+
export * from './entries';
|
|
114
|
+
export * from './marketplace-app';
|
|
115
|
+
export type ExtensionType = {
|
|
116
|
+
uid: string;
|
|
117
|
+
scope: Record<string, unknown>;
|
|
118
|
+
title: string;
|
|
119
|
+
};
|
|
@@ -128,7 +128,7 @@ const removeReferenceFields = async function (schema, flag = { supressed: false
|
|
|
128
128
|
catch (error) {
|
|
129
129
|
// Else warn and modify the schema object.
|
|
130
130
|
isContentTypeError = true;
|
|
131
|
-
cli_utilities_1.log.warn(`Content
|
|
131
|
+
cli_utilities_1.log.warn(`Content type ${schema[i].reference_to[j]} does not exist. Removing the field from schema...`);
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
134
|
if (isContentTypeError) {
|
|
@@ -200,7 +200,7 @@ const updateFieldRules = function (contentType) {
|
|
|
200
200
|
const field = contentType.schema[i];
|
|
201
201
|
fieldDataTypeMap[field.uid] = field.data_type;
|
|
202
202
|
}
|
|
203
|
-
cli_utilities_1.log.debug(`Created field data type mapping for ${Object.keys(fieldDataTypeMap).length} fields
|
|
203
|
+
cli_utilities_1.log.debug(`Created field data type mapping for ${Object.keys(fieldDataTypeMap).length} fields.`);
|
|
204
204
|
const fieldRules = [...contentType.field_rules];
|
|
205
205
|
let len = fieldRules.length;
|
|
206
206
|
let removedRules = 0;
|
package/lib/utils/file-helper.js
CHANGED
|
@@ -26,7 +26,7 @@ const setupConfig = async (importCmdFlags) => {
|
|
|
26
26
|
config.contentDir = (0, cli_utilities_1.sanitizePath)(importCmdFlags['data'] || importCmdFlags['data-dir'] || config.data || (await (0, interactive_1.askContentDir)()));
|
|
27
27
|
const pattern = /[*$%#<>{}!&?]/g;
|
|
28
28
|
if (pattern.test(config.contentDir)) {
|
|
29
|
-
cli_utilities_1.cliux.print(`\nPlease
|
|
29
|
+
cli_utilities_1.cliux.print(`\nPlease enter a directory path without any special characters: (*,&,{,},[,],$,%,<,>,?,!)`, {
|
|
30
30
|
color: 'yellow',
|
|
31
31
|
});
|
|
32
32
|
config.contentDir = (0, cli_utilities_1.sanitizePath)(await (0, interactive_1.askContentDir)());
|
|
@@ -117,7 +117,7 @@ const setupConfig = async (importCmdFlags) => {
|
|
|
117
117
|
cli_utilities_1.configHandler.set('log.progressSupportedModule', 'import');
|
|
118
118
|
// Add authentication details to config for context tracking
|
|
119
119
|
config.authenticationMethod = authenticationMethod;
|
|
120
|
-
cli_utilities_1.log.debug('Import configuration setup completed', Object.assign({}, config));
|
|
120
|
+
cli_utilities_1.log.debug('Import configuration setup completed.', Object.assign({}, config));
|
|
121
121
|
return config;
|
|
122
122
|
};
|
|
123
123
|
exports.default = setupConfig;
|
|
@@ -116,7 +116,30 @@ const updateImportConfigWithResolvedPath = async (importConfig, resolvedPath) =>
|
|
|
116
116
|
importConfig.branchDir = resolvedPath;
|
|
117
117
|
importConfig.contentDir = resolvedPath;
|
|
118
118
|
importConfig.data = resolvedPath;
|
|
119
|
-
|
|
119
|
+
// Check if export-info.json exists to determine contentVersion
|
|
120
|
+
const exportInfoPath = path.join(resolvedPath, 'export-info.json');
|
|
121
|
+
if ((0, file_helper_1.fileExistsSync)(exportInfoPath)) {
|
|
122
|
+
try {
|
|
123
|
+
const exportInfo = await (0, file_helper_1.readFile)(exportInfoPath);
|
|
124
|
+
// If export-info.json exists, set contentVersion to 2 (or use value from file if present)
|
|
125
|
+
if (exportInfo && exportInfo.contentVersion) {
|
|
126
|
+
importConfig.contentVersion = exportInfo.contentVersion;
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
// If export-info.json exists but contentVersion is missing, default to 2
|
|
130
|
+
importConfig.contentVersion = 2;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
// If export-info.json exists but is null or can't be read, default to 2
|
|
135
|
+
importConfig.contentVersion = 2;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
// If export-info.json doesn't exist, default to 1 (legacy format)
|
|
140
|
+
importConfig.contentVersion = 1;
|
|
141
|
+
}
|
|
142
|
+
cli_utilities_1.log.debug(`Import config updated - contentDir: ${importConfig.contentDir}, branchDir: ${importConfig.branchDir}, data: ${importConfig.data}, contentVersion: ${importConfig.contentVersion}`);
|
|
120
143
|
};
|
|
121
144
|
exports.updateImportConfigWithResolvedPath = updateImportConfigWithResolvedPath;
|
|
122
145
|
/**
|
|
@@ -44,7 +44,7 @@ const login = async (config) => {
|
|
|
44
44
|
let errorstack_key = (_a = error === null || error === void 0 ? void 0 : error.errors) === null || _a === void 0 ? void 0 : _a.api_key;
|
|
45
45
|
if (errorstack_key) {
|
|
46
46
|
const keyError = errorstack_key[0];
|
|
47
|
-
cli_utilities_1.log.error(`Invalid stack API token: ${keyError} Please enter valid stack API token.`);
|
|
47
|
+
cli_utilities_1.log.error(`Invalid stack API token: ${keyError}. Please enter a valid stack API token.`);
|
|
48
48
|
throw error;
|
|
49
49
|
}
|
|
50
50
|
cli_utilities_1.log.error(`Stack fetch error: ${error === null || error === void 0 ? void 0 : error.errorMessage}`);
|
|
@@ -21,6 +21,7 @@ const getAllStackSpecificApps = async (config, skip = 0, listOfApps = []) => {
|
|
|
21
21
|
.fetchAll({ target_uids: config.target_stack, skip })
|
|
22
22
|
.catch((error) => {
|
|
23
23
|
(0, cli_utilities_1.handleAndLogError)(error);
|
|
24
|
+
cli_utilities_1.log.error(error, config === null || config === void 0 ? void 0 : config.context);
|
|
24
25
|
});
|
|
25
26
|
if (collection) {
|
|
26
27
|
const { items: apps, count } = collection;
|
|
@@ -56,7 +57,8 @@ const getOrgUid = async (config) => {
|
|
|
56
57
|
.stack({ api_key: config.target_stack })
|
|
57
58
|
.fetch()
|
|
58
59
|
.catch((error) => {
|
|
59
|
-
|
|
60
|
+
(0, cli_utilities_1.handleAndLogError)(error);
|
|
61
|
+
cli_utilities_1.log.error(error, config === null || config === void 0 ? void 0 : config.context);
|
|
60
62
|
});
|
|
61
63
|
const orgUid = (tempStackData === null || tempStackData === void 0 ? void 0 : tempStackData.org_uid) || '';
|
|
62
64
|
cli_utilities_1.log.debug(`Organization UID: ${orgUid}`);
|
|
@@ -78,7 +80,7 @@ const getConfirmationToCreateApps = async (privateApps, config) => {
|
|
|
78
80
|
return Promise.resolve(true);
|
|
79
81
|
}
|
|
80
82
|
else {
|
|
81
|
-
cli_utilities_1.log.
|
|
83
|
+
cli_utilities_1.log.debug('User declined to create private apps (second prompt).');
|
|
82
84
|
return Promise.resolve(false);
|
|
83
85
|
}
|
|
84
86
|
}
|
|
@@ -89,7 +91,7 @@ const getConfirmationToCreateApps = async (privateApps, config) => {
|
|
|
89
91
|
}
|
|
90
92
|
}
|
|
91
93
|
else {
|
|
92
|
-
cli_utilities_1.log.
|
|
94
|
+
cli_utilities_1.log.debug('Force prompt disabled, automatically creating private apps');
|
|
93
95
|
return Promise.resolve(true);
|
|
94
96
|
}
|
|
95
97
|
};
|
|
@@ -111,7 +113,7 @@ const makeRedirectUrlCall = async (response, appName, config) => {
|
|
|
111
113
|
.get(response.redirect_url)
|
|
112
114
|
.then(async ({ response }) => {
|
|
113
115
|
if ((0, includes_1.default)([501, 403], response.status)) {
|
|
114
|
-
cli_utilities_1.log.error(`OAuth API call failed for ${appName}: ${response.statusText}
|
|
116
|
+
cli_utilities_1.log.error(`OAuth API call failed for ${appName}: ${response.statusText}`, config === null || config === void 0 ? void 0 : config.context);
|
|
115
117
|
await (0, exports.confirmToCloseProcess)(response.data, config);
|
|
116
118
|
}
|
|
117
119
|
else {
|
|
@@ -119,6 +121,7 @@ const makeRedirectUrlCall = async (response, appName, config) => {
|
|
|
119
121
|
}
|
|
120
122
|
})
|
|
121
123
|
.catch((error) => {
|
|
124
|
+
cli_utilities_1.log.error(error, config === null || config === void 0 ? void 0 : config.context);
|
|
122
125
|
if ((0, includes_1.default)([501, 403], error.status)) {
|
|
123
126
|
(0, cli_utilities_1.handleAndLogError)(error);
|
|
124
127
|
}
|
|
@@ -14,7 +14,7 @@ const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
|
14
14
|
* @param {ImportConfig} importConfig
|
|
15
15
|
*/
|
|
16
16
|
const lookUpTaxonomy = function (importConfig, schema, taxonomies) {
|
|
17
|
-
cli_utilities_1.log.debug(`Starting taxonomy lookup for schema with ${Object.keys(schema).length} fields
|
|
17
|
+
cli_utilities_1.log.debug(`Starting taxonomy lookup for schema with ${Object.keys(schema).length} fields.`);
|
|
18
18
|
for (let i in schema) {
|
|
19
19
|
if (schema[i].data_type === 'taxonomy') {
|
|
20
20
|
cli_utilities_1.log.debug(`Processing taxonomy field: ${schema[i].uid}`);
|
package/messages/index.json
CHANGED
|
@@ -1 +1,10 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"COMPOSABLE_STUDIO_IMPORT_START": "Starting Studio project import...",
|
|
3
|
+
"COMPOSABLE_STUDIO_NOT_FOUND": "No Studio project found in exported data",
|
|
4
|
+
"COMPOSABLE_STUDIO_SKIP_EXISTING": "Skipping Studio import - target stack already has a connected project",
|
|
5
|
+
"COMPOSABLE_STUDIO_IMPORT_COMPLETE": "Successfully imported Studio project '%s'",
|
|
6
|
+
"COMPOSABLE_STUDIO_IMPORT_FAILED": "Failed to import Studio project: %s",
|
|
7
|
+
"COMPOSABLE_STUDIO_NAME_CONFLICT": "Project name '%s' already exists. Please provide a new name:",
|
|
8
|
+
"COMPOSABLE_STUDIO_SUGGEST_NAME": "Suggested name: %s",
|
|
9
|
+
"COMPOSABLE_STUDIO_ENV_MAPPING_FAILED": "Warning: Could not map environment '%s', using empty environment"
|
|
10
|
+
}
|
package/oclif.manifest.json
CHANGED
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
},
|
|
85
85
|
"module": {
|
|
86
86
|
"char": "m",
|
|
87
|
-
"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, and
|
|
87
|
+
"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.",
|
|
88
88
|
"name": "module",
|
|
89
89
|
"required": false,
|
|
90
90
|
"hasDynamicHelp": false,
|
|
@@ -212,5 +212,5 @@
|
|
|
212
212
|
]
|
|
213
213
|
}
|
|
214
214
|
},
|
|
215
|
-
"version": "2.0.0-beta.
|
|
215
|
+
"version": "2.0.0-beta.3"
|
|
216
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": "2.0.0-beta.
|
|
4
|
+
"version": "2.0.0-beta.3",
|
|
5
5
|
"author": "Contentstack",
|
|
6
6
|
"bugs": "https://github.com/contentstack/cli/issues",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@contentstack/cli-audit": "
|
|
9
|
-
"@contentstack/cli-command": "~1.
|
|
8
|
+
"@contentstack/cli-audit": "2.0.0-beta",
|
|
9
|
+
"@contentstack/cli-command": "~1.7.0",
|
|
10
10
|
"@contentstack/cli-utilities": "~1.15.0",
|
|
11
11
|
"@contentstack/management": "~1.22.0",
|
|
12
|
-
"@contentstack/cli-variants": "~2.0.0-beta",
|
|
12
|
+
"@contentstack/cli-variants": "~2.0.0-beta.3",
|
|
13
13
|
"@oclif/core": "^4.3.0",
|
|
14
14
|
"big-json": "^3.2.0",
|
|
15
15
|
"bluebird": "^3.7.2",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"@types/mkdirp": "^1.0.2",
|
|
33
33
|
"@types/mocha": "^8.2.3",
|
|
34
34
|
"@types/node": "^14.18.63",
|
|
35
|
+
"@types/rewire": "^2.5.30",
|
|
35
36
|
"@types/tar": "^6.1.13",
|
|
36
37
|
"@types/uuid": "^9.0.8",
|
|
37
38
|
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
|
@@ -40,6 +41,7 @@
|
|
|
40
41
|
"mocha": "^10.8.2",
|
|
41
42
|
"nyc": "^15.1.0",
|
|
42
43
|
"oclif": "^4.17.46",
|
|
44
|
+
"rewire": "^9.0.1",
|
|
43
45
|
"ts-node": "^10.9.2",
|
|
44
46
|
"typescript": "^4.9.5"
|
|
45
47
|
},
|
|
@@ -57,7 +59,8 @@
|
|
|
57
59
|
"lint": "eslint src/**/*.ts",
|
|
58
60
|
"format": "eslint src/**/*.ts --fix",
|
|
59
61
|
"test:integration": "mocha --forbid-only \"test/run.test.js\" --integration-test --timeout 60000",
|
|
60
|
-
"test:unit": "mocha --forbid-only \"test/unit
|
|
62
|
+
"test:unit:report": "nyc --extension .ts mocha --forbid-only \"test/unit/**/*.test.ts\"",
|
|
63
|
+
"test:unit": "mocha --forbid-only \"test/**/*.test.ts\" --exit"
|
|
61
64
|
},
|
|
62
65
|
"engines": {
|
|
63
66
|
"node": ">=14.0.0"
|