@contentstack/cli-cm-clone 1.1.3 → 1.1.5
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 +3 -3
- package/oclif.manifest.json +1 -1
- package/package.json +8 -8
- package/src/commands/cm/stacks/clone.js +3 -3
- package/src/lib/util/clone-handler.js +59 -50
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ $ npm install -g @contentstack/cli-cm-clone
|
|
|
15
15
|
$ csdx COMMAND
|
|
16
16
|
running command...
|
|
17
17
|
$ csdx (-v|--version|version)
|
|
18
|
-
@contentstack/cli-cm-clone/1.1.
|
|
18
|
+
@contentstack/cli-cm-clone/1.1.5 linux-x64 node-v16.18.1
|
|
19
19
|
$ csdx --help [COMMAND]
|
|
20
20
|
USAGE
|
|
21
21
|
$ csdx COMMAND
|
|
@@ -49,14 +49,14 @@ OPTIONS
|
|
|
49
49
|
-n, --stack-name=stack-name Name for the new stack to store the cloned
|
|
50
50
|
content.
|
|
51
51
|
|
|
52
|
-
-y, --yes [
|
|
52
|
+
-y, --yes [Optional] Override marketplace prompts
|
|
53
53
|
|
|
54
54
|
--destination-management-token-alias=destination-management-token-alias Source API key of the target stack token
|
|
55
55
|
alias.
|
|
56
56
|
|
|
57
57
|
--destination-stack-api-key=destination-stack-api-key Destination stack API Key
|
|
58
58
|
|
|
59
|
-
--import-webhook-status=disable|current [default: disable] Webhook state
|
|
59
|
+
--import-webhook-status=disable|current [default: disable] [Optional] Webhook state
|
|
60
60
|
|
|
61
61
|
--source-branch=source-branch Branch of the source stack.
|
|
62
62
|
|
package/oclif.manifest.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"1.1.
|
|
1
|
+
{"version":"1.1.5","commands":{"cm:stacks:clone":{"id":"cm:stacks:clone","description":"Clone data (structure/content or both) of a stack into another stack\nUse this plugin to automate the process of cloning a stack in few steps.\n","usage":"cm:stacks:clone [--source-branch <value>] [--target-branch <value>] [--source-management-token-alias <value>] [--destination-management-token-alias <value>] [-n <value>] [--type a|b] [--source-stack-api-key <value>] [--destination-stack-api-key <value>] [--import-webhook-status disable|current]","pluginName":"@contentstack/cli-cm-clone","pluginType":"core","aliases":["cm:stack-clone"],"examples":["csdx cm:stacks:clone","csdx cm:stacks:clone --source-branch <source-branch-name> --target-branch <target-branch-name> --yes","csdx cm:stacks:clone --source-stack-api-key <apiKey> --destination-stack-api-key <apiKey>","csdx cm:stacks:clone --source-management-token-alias <management token alias> --destination-management-token-alias <management token alias>","csdx cm:stacks:clone --source-branch --target-branch --source-management-token-alias <management token alias> --destination-management-token-alias <management token alias>","csdx cm:stacks:clone --source-branch --target-branch --source-management-token-alias <management token alias> --destination-management-token-alias <management token alias> --type <value a or b>"],"flags":{"source-branch":{"name":"source-branch","type":"option","description":"Branch of the source stack.","required":false},"target-branch":{"name":"target-branch","type":"option","description":"Branch of the target stack.","required":false},"source-management-token-alias":{"name":"source-management-token-alias","type":"option","description":"Source API key of the target stack token alias.","required":false},"destination-management-token-alias":{"name":"destination-management-token-alias","type":"option","description":"Source API key of the target stack token alias.","required":false},"stack-name":{"name":"stack-name","type":"option","char":"n","description":"Name for the new stack to store the cloned content.","required":false},"type":{"name":"type","type":"option","description":"Type of data to clone\na) Structure (all modules except entries & assets)\nb) Structure with content (all modules including entries & assets)\n ","required":false,"options":["a","b"]},"source-stack-api-key":{"name":"source-stack-api-key","type":"option","description":"Source stack API Key"},"destination-stack-api-key":{"name":"destination-stack-api-key","type":"option","description":"Destination stack API Key"},"import-webhook-status":{"name":"import-webhook-status","type":"option","description":"[Optional] Webhook state","required":false,"options":["disable","current"],"default":"disable"},"yes":{"name":"yes","type":"boolean","char":"y","description":"[Optional] Override marketplace prompts","required":false,"allowNo":false}},"args":[]}}}
|
package/package.json
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentstack/cli-cm-clone",
|
|
3
3
|
"description": "Contentstack stack clone plugin",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.5",
|
|
5
5
|
"author": "Contentstack",
|
|
6
6
|
"bugs": "https://github.com/rohitmishra209/cli-cm-clone/issues",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@contentstack/cli-cm-export": "^1.2.
|
|
9
|
-
"@contentstack/cli-cm-import": "^1.2.
|
|
10
|
-
"@contentstack/cli-command": "^1.0.
|
|
11
|
-
"@contentstack/cli-utilities": "^1.0.
|
|
12
|
-
"@contentstack/management": "^1.
|
|
8
|
+
"@contentstack/cli-cm-export": "^1.2.2",
|
|
9
|
+
"@contentstack/cli-cm-import": "^1.2.3",
|
|
10
|
+
"@contentstack/cli-command": "^1.0.3",
|
|
11
|
+
"@contentstack/cli-utilities": "^1.0.4",
|
|
12
|
+
"@contentstack/management": "^1.6.0",
|
|
13
13
|
"@oclif/command": "^1.8.16",
|
|
14
14
|
"@oclif/config": "^1.18.3",
|
|
15
15
|
"chalk": "^4.1.0",
|
|
16
16
|
"async": "^3.2.4",
|
|
17
17
|
"child_process": "^1.0.2",
|
|
18
18
|
"fancy-test": "^1.4.10",
|
|
19
|
-
"inquirer": "
|
|
19
|
+
"inquirer": "8.2.4",
|
|
20
20
|
"ora": "^5.1.0",
|
|
21
21
|
"rimraf": "^3.0.2",
|
|
22
22
|
"winston": "^3.7.2"
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"globby": "^10.0.2",
|
|
32
32
|
"jest": "^26.6.3",
|
|
33
33
|
"mocha": "^10.0.0",
|
|
34
|
-
"nyc": "^
|
|
34
|
+
"nyc": "^15.1.0",
|
|
35
35
|
"sinon": "^9.2.4"
|
|
36
36
|
},
|
|
37
37
|
"engines": {
|
|
@@ -29,7 +29,7 @@ class StackCloneCommand extends Command {
|
|
|
29
29
|
const handleClone = async () => {
|
|
30
30
|
const listOfTokens = configHandler.get('tokens');
|
|
31
31
|
|
|
32
|
-
config.
|
|
32
|
+
config.forceStopMarketplaceAppsPrompt = yes;
|
|
33
33
|
|
|
34
34
|
if (cloneType) {
|
|
35
35
|
config.cloneType = cloneType;
|
|
@@ -232,7 +232,7 @@ b) Structure with content (all modules including entries & assets)
|
|
|
232
232
|
description: 'Destination stack API Key',
|
|
233
233
|
}),
|
|
234
234
|
'import-webhook-status': flags.string({
|
|
235
|
-
description: 'Webhook state',
|
|
235
|
+
description: '[Optional] Webhook state',
|
|
236
236
|
options: ['disable', 'current'],
|
|
237
237
|
required: false,
|
|
238
238
|
default: 'disable',
|
|
@@ -240,7 +240,7 @@ b) Structure with content (all modules including entries & assets)
|
|
|
240
240
|
yes: flags.boolean({
|
|
241
241
|
char: 'y',
|
|
242
242
|
required: false,
|
|
243
|
-
description: '[
|
|
243
|
+
description: '[Optional] Override marketplace prompts',
|
|
244
244
|
}),
|
|
245
245
|
};
|
|
246
246
|
|
|
@@ -12,8 +12,15 @@ const defaultConfig = require('@contentstack/cli-cm-export/src/config/default');
|
|
|
12
12
|
const { CustomAbortController } = require('./abort-controller');
|
|
13
13
|
|
|
14
14
|
const {
|
|
15
|
-
HandleOrgCommand,
|
|
16
|
-
|
|
15
|
+
HandleOrgCommand,
|
|
16
|
+
HandleStackCommand,
|
|
17
|
+
HandleDestinationStackCommand,
|
|
18
|
+
HandleExportCommand,
|
|
19
|
+
SetBranchCommand,
|
|
20
|
+
CreateNewStackCommand,
|
|
21
|
+
CloneTypeSelectionCommand,
|
|
22
|
+
Clone,
|
|
23
|
+
HandleBranchCommand,
|
|
17
24
|
} = require('../helpers/command-helpers');
|
|
18
25
|
|
|
19
26
|
let client = {};
|
|
@@ -85,7 +92,7 @@ class CloneHandler {
|
|
|
85
92
|
let keyPressHandler;
|
|
86
93
|
return new Promise(async (resolve, reject) => {
|
|
87
94
|
try {
|
|
88
|
-
const { org = {}, msg = '', isSource = true, stackAbortController } = options || {}
|
|
95
|
+
const { org = {}, msg = '', isSource = true, stackAbortController } = options || {};
|
|
89
96
|
|
|
90
97
|
keyPressHandler = async function (_ch, key) {
|
|
91
98
|
if (key.name === 'left' && key.shift) {
|
|
@@ -97,7 +104,7 @@ class CloneHandler {
|
|
|
97
104
|
};
|
|
98
105
|
process.stdin.addListener('keypress', keyPressHandler);
|
|
99
106
|
|
|
100
|
-
const stackList = await this.getStack(org, msg, isSource).catch(reject)
|
|
107
|
+
const stackList = await this.getStack(org, msg, isSource).catch(reject);
|
|
101
108
|
|
|
102
109
|
if (stackList) {
|
|
103
110
|
const ui = new inquirer.ui.BottomBar();
|
|
@@ -117,7 +124,7 @@ class CloneHandler {
|
|
|
117
124
|
config.destinationStackName = selectedStack.stack;
|
|
118
125
|
}
|
|
119
126
|
|
|
120
|
-
resolve(selectedStack)
|
|
127
|
+
resolve(selectedStack);
|
|
121
128
|
}
|
|
122
129
|
} catch (error) {
|
|
123
130
|
return reject(error);
|
|
@@ -130,48 +137,42 @@ class CloneHandler {
|
|
|
130
137
|
}
|
|
131
138
|
|
|
132
139
|
handleBranchSelection = async (options) => {
|
|
133
|
-
const { api_key, isSource = true, returnBranch = false } = options
|
|
134
|
-
const baseUrl = defaultConfig.host.startsWith('http')
|
|
135
|
-
? defaultConfig.host
|
|
136
|
-
: `https://${defaultConfig.host}/v3`;
|
|
140
|
+
const { api_key, isSource = true, returnBranch = false } = options;
|
|
141
|
+
const baseUrl = defaultConfig.host.startsWith('http') ? defaultConfig.host : `https://${defaultConfig.host}/v3`;
|
|
137
142
|
|
|
138
143
|
return new Promise(async (resolve, reject) => {
|
|
139
144
|
try {
|
|
140
|
-
const headers = { api_key }
|
|
145
|
+
const headers = { api_key };
|
|
141
146
|
|
|
142
147
|
if (config.auth_token) {
|
|
143
|
-
headers['authtoken'] = config.auth_token
|
|
148
|
+
headers['authtoken'] = config.auth_token;
|
|
144
149
|
} else if (config.management_token) {
|
|
145
|
-
headers['authorization'] = config.management_token
|
|
150
|
+
headers['authorization'] = config.management_token;
|
|
146
151
|
}
|
|
147
152
|
|
|
148
153
|
// NOTE validate if source branch is exist
|
|
149
154
|
if (isSource && config.sourceStackBranch) {
|
|
150
|
-
await this.validateIfBranchExist(headers, true)
|
|
151
|
-
return resolve()
|
|
155
|
+
await this.validateIfBranchExist(headers, true);
|
|
156
|
+
return resolve();
|
|
152
157
|
}
|
|
153
158
|
|
|
154
159
|
// NOTE Validate target branch is exist
|
|
155
160
|
if (!isSource && config.targetStackBranch) {
|
|
156
|
-
await this.validateIfBranchExist(headers, false)
|
|
157
|
-
return resolve()
|
|
161
|
+
await this.validateIfBranchExist(headers, false);
|
|
162
|
+
return resolve();
|
|
158
163
|
}
|
|
159
164
|
|
|
160
165
|
const spinner = ora('Fetching Branches').start();
|
|
161
166
|
const result = await new HttpClient()
|
|
162
167
|
.headers(headers)
|
|
163
168
|
.get(`${baseUrl}/stacks/branches`)
|
|
164
|
-
.then(({ data: { branches } }) => branches)
|
|
169
|
+
.then(({ data: { branches } }) => branches);
|
|
165
170
|
|
|
166
|
-
const condition = (
|
|
167
|
-
result &&
|
|
168
|
-
Array.isArray(result) &&
|
|
169
|
-
result.length > 0
|
|
170
|
-
)
|
|
171
|
+
const condition = result && Array.isArray(result) && result.length > 0;
|
|
171
172
|
|
|
172
173
|
// NOTE if want to get only list of branches (Pass param -> returnBranch = true )
|
|
173
174
|
if (returnBranch) {
|
|
174
|
-
resolve(condition ? result : [])
|
|
175
|
+
resolve(condition ? result : []);
|
|
175
176
|
} else {
|
|
176
177
|
// NOTE list options to use to select branch
|
|
177
178
|
if (condition) {
|
|
@@ -180,30 +181,30 @@ class CloneHandler {
|
|
|
180
181
|
type: 'list',
|
|
181
182
|
name: 'branch',
|
|
182
183
|
message: 'Choose a branch',
|
|
183
|
-
choices: result.map(row => row.uid),
|
|
184
|
+
choices: result.map((row) => row.uid),
|
|
184
185
|
});
|
|
185
186
|
|
|
186
187
|
if (isSource) {
|
|
187
|
-
config.sourceStackBranch = branch
|
|
188
|
+
config.sourceStackBranch = branch;
|
|
188
189
|
} else {
|
|
189
|
-
config.targetStackBranch = branch
|
|
190
|
+
config.targetStackBranch = branch;
|
|
190
191
|
}
|
|
191
192
|
} else {
|
|
192
193
|
spinner.succeed('No branches found.!');
|
|
193
194
|
}
|
|
194
195
|
|
|
195
|
-
resolve()
|
|
196
|
+
resolve();
|
|
196
197
|
}
|
|
197
198
|
} catch (e) {
|
|
198
199
|
spinner.fail();
|
|
199
|
-
console.log(e && e.message)
|
|
200
|
-
resolve()
|
|
200
|
+
console.log(e && e.message);
|
|
201
|
+
resolve();
|
|
201
202
|
}
|
|
202
|
-
})
|
|
203
|
-
}
|
|
203
|
+
});
|
|
204
|
+
};
|
|
204
205
|
|
|
205
206
|
async validateIfBranchExist(headers, isSource) {
|
|
206
|
-
const branch = isSource ? config.sourceStackBranch : config.targetStackBranch
|
|
207
|
+
const branch = isSource ? config.sourceStackBranch : config.targetStackBranch;
|
|
207
208
|
const spinner = ora(`Validation if ${isSource ? 'source' : 'target'} branch exist.!`).start();
|
|
208
209
|
const isBranchExist = await HttpClient.create()
|
|
209
210
|
.headers(headers)
|
|
@@ -211,15 +212,15 @@ class CloneHandler {
|
|
|
211
212
|
.then(({ data }) => data);
|
|
212
213
|
|
|
213
214
|
const completeSpinner = (msg, method = 'succeed') => {
|
|
214
|
-
spinner[method](msg)
|
|
215
|
-
spinner.stop()
|
|
216
|
-
}
|
|
215
|
+
spinner[method](msg);
|
|
216
|
+
spinner.stop();
|
|
217
|
+
};
|
|
217
218
|
|
|
218
219
|
if (isBranchExist && typeof isBranchExist === 'object' && typeof isBranchExist.branch === 'object') {
|
|
219
|
-
completeSpinner(`${isSource ? 'Source' : 'Target'} branch verified.!`)
|
|
220
|
+
completeSpinner(`${isSource ? 'Source' : 'Target'} branch verified.!`);
|
|
220
221
|
} else {
|
|
221
|
-
completeSpinner(`${isSource ? 'Source' : 'Target'} branch not found.!`, 'fail')
|
|
222
|
-
process.exit()
|
|
222
|
+
completeSpinner(`${isSource ? 'Source' : 'Target'} branch not found.!`, 'fail');
|
|
223
|
+
process.exit();
|
|
223
224
|
}
|
|
224
225
|
}
|
|
225
226
|
|
|
@@ -236,12 +237,12 @@ class CloneHandler {
|
|
|
236
237
|
|
|
237
238
|
const org = await cloneCommand.execute(new HandleOrgCommand({ msg: orgMsg, isSource: true }, this));
|
|
238
239
|
if (org) {
|
|
239
|
-
const sourceStack = await cloneCommand.execute(
|
|
240
|
+
const sourceStack = await cloneCommand.execute(
|
|
241
|
+
new HandleStackCommand({ org, isSource: true, msg: stackMsg, stackAbortController }, this),
|
|
242
|
+
);
|
|
240
243
|
|
|
241
244
|
if (config.source_stack) {
|
|
242
|
-
await cloneCommand.execute(
|
|
243
|
-
new HandleBranchCommand({ api_key: config.source_stack }, this)
|
|
244
|
-
);
|
|
245
|
+
await cloneCommand.execute(new HandleBranchCommand({ api_key: config.source_stack }, this));
|
|
245
246
|
}
|
|
246
247
|
|
|
247
248
|
if (stackAbortController.signal.aborted) {
|
|
@@ -256,7 +257,9 @@ class CloneHandler {
|
|
|
256
257
|
await cloneCommand.execute(new SetBranchCommand(null, this));
|
|
257
258
|
|
|
258
259
|
if (exportRes) {
|
|
259
|
-
this.executeDestination().catch(() => {
|
|
260
|
+
this.executeDestination().catch(() => {
|
|
261
|
+
reject();
|
|
262
|
+
});
|
|
260
263
|
}
|
|
261
264
|
return resolve();
|
|
262
265
|
} catch (error) {
|
|
@@ -288,13 +291,17 @@ class CloneHandler {
|
|
|
288
291
|
|
|
289
292
|
if (org) {
|
|
290
293
|
const stackMsg = 'Choose the destination stack:';
|
|
291
|
-
await cloneCommand.execute(
|
|
294
|
+
await cloneCommand.execute(
|
|
295
|
+
new HandleDestinationStackCommand({ org, msg: stackMsg, stackAbortController, isSource: false }, this),
|
|
296
|
+
);
|
|
292
297
|
}
|
|
293
298
|
}
|
|
294
299
|
|
|
295
300
|
// NOTE GET list of branches if branches enabled
|
|
296
301
|
if (config.target_stack) {
|
|
297
|
-
await cloneCommand.execute(
|
|
302
|
+
await cloneCommand.execute(
|
|
303
|
+
new HandleBranchCommand({ isSource: false, api_key: config.target_stack }, this),
|
|
304
|
+
);
|
|
298
305
|
}
|
|
299
306
|
} else {
|
|
300
307
|
const orgMsg = 'Choose an organization where you want to create a stack: ';
|
|
@@ -316,7 +323,7 @@ class CloneHandler {
|
|
|
316
323
|
});
|
|
317
324
|
}
|
|
318
325
|
}
|
|
319
|
-
})
|
|
326
|
+
});
|
|
320
327
|
}
|
|
321
328
|
|
|
322
329
|
async setBranch() {
|
|
@@ -327,7 +334,7 @@ class CloneHandler {
|
|
|
327
334
|
if (branches && branches.items && branches.items.length) {
|
|
328
335
|
config.sourceStackBranch = 'main';
|
|
329
336
|
}
|
|
330
|
-
} catch (_error) {
|
|
337
|
+
} catch (_error) {}
|
|
331
338
|
}
|
|
332
339
|
}
|
|
333
340
|
|
|
@@ -353,7 +360,7 @@ class CloneHandler {
|
|
|
353
360
|
return reject(e);
|
|
354
361
|
}
|
|
355
362
|
});
|
|
356
|
-
}
|
|
363
|
+
}
|
|
357
364
|
|
|
358
365
|
async getStack(answer, stkMessage) {
|
|
359
366
|
return new Promise(async (resolve, reject) => {
|
|
@@ -386,7 +393,7 @@ class CloneHandler {
|
|
|
386
393
|
return reject(e);
|
|
387
394
|
}
|
|
388
395
|
});
|
|
389
|
-
}
|
|
396
|
+
}
|
|
390
397
|
|
|
391
398
|
async createNewStack(options) {
|
|
392
399
|
let keyPressHandler;
|
|
@@ -494,6 +501,8 @@ class CloneHandler {
|
|
|
494
501
|
cmd.push('--branch', config.sourceStackBranch);
|
|
495
502
|
}
|
|
496
503
|
|
|
504
|
+
if (config.forceStopMarketplaceAppsPrompt) cmd.push('-y');
|
|
505
|
+
|
|
497
506
|
let exportData = exportCmd.run(cmd);
|
|
498
507
|
exportData.then(() => resolve(true)).catch(reject);
|
|
499
508
|
});
|
|
@@ -516,7 +525,7 @@ class CloneHandler {
|
|
|
516
525
|
cmd.push('--import-webhook-status', config.importWebhookStatus);
|
|
517
526
|
}
|
|
518
527
|
|
|
519
|
-
if (config.
|
|
528
|
+
if (config.forceStopMarketplaceAppsPrompt) cmd.push('-y');
|
|
520
529
|
|
|
521
530
|
await importCmd.run(cmd);
|
|
522
531
|
return resolve();
|