@contentstack/cli-cm-clone 1.0.0 → 1.1.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/package.json
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentstack/cli-cm-clone",
|
|
3
3
|
"description": "Contentstack stack clone plugin",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.1.0",
|
|
5
5
|
"author": "Contentstack",
|
|
6
6
|
"bugs": "https://github.com/rohitmishra209/cli-cm-clone/issues",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@contentstack/cli-cm-export": "^1.
|
|
9
|
-
"@contentstack/cli-cm-import": "^1.
|
|
10
|
-
"@contentstack/cli-command": "^1.0.
|
|
8
|
+
"@contentstack/cli-cm-export": "^1.1.0",
|
|
9
|
+
"@contentstack/cli-cm-import": "^1.1.0",
|
|
10
|
+
"@contentstack/cli-command": "^1.0.1",
|
|
11
|
+
"@contentstack/cli-utilities": "^1.0.2",
|
|
11
12
|
"@contentstack/management": "^1.3.0",
|
|
12
|
-
"@contentstack/cli-utilities": "^1.0.0",
|
|
13
13
|
"@oclif/command": "^1.8.16",
|
|
14
14
|
"@oclif/config": "^1.18.3",
|
|
15
|
+
"chalk": "^4.1.0",
|
|
15
16
|
"async": "^3.2.4",
|
|
16
17
|
"child_process": "^1.0.2",
|
|
17
18
|
"fancy-test": "^1.4.10",
|
|
@@ -65,4 +66,4 @@
|
|
|
65
66
|
"cm:stack-clone": "csdx cm:stacks:clone"
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
|
-
}
|
|
69
|
+
}
|
|
@@ -23,6 +23,7 @@ class StackCloneCommand extends Command {
|
|
|
23
23
|
'source-management-token-alias': sourceManagementTokenAlias,
|
|
24
24
|
'destination-management-token-alias': destinationManagementTokenAlias,
|
|
25
25
|
'import-webhook-status': importWebhookStatus,
|
|
26
|
+
'master-locale': masterLocale
|
|
26
27
|
} = cloneCommandFlags;
|
|
27
28
|
|
|
28
29
|
const handleClone = async () => {
|
|
@@ -67,14 +68,16 @@ class StackCloneCommand extends Command {
|
|
|
67
68
|
await this.removeContentDirIfNotEmptyBeforeClone(pathdir); // NOTE remove if folder not empty before clone
|
|
68
69
|
this.registerCleanupOnInterrupt(pathdir);
|
|
69
70
|
|
|
71
|
+
if (masterLocale) {
|
|
72
|
+
config.master_locale = { code: masterLocale }
|
|
73
|
+
}
|
|
70
74
|
config.auth_token = _authToken;
|
|
71
75
|
config.host = this.cmaHost;
|
|
72
76
|
config.cdn = this.cdaHost;
|
|
77
|
+
config.pathDir = pathdir;
|
|
73
78
|
const cloneHandler = new CloneHandler(config);
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
await this.cleanUp(pathdir, successMessage);
|
|
77
|
-
};
|
|
79
|
+
cloneHandler.execute().catch();
|
|
80
|
+
}
|
|
78
81
|
|
|
79
82
|
if (sourceManagementTokenAlias && destinationManagementTokenAlias) {
|
|
80
83
|
if (sourceStackBranch || targetStackBranch) {
|
|
@@ -94,9 +97,11 @@ class StackCloneCommand extends Command {
|
|
|
94
97
|
this.exit(1);
|
|
95
98
|
}
|
|
96
99
|
} catch (error) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
+
if (error) {
|
|
101
|
+
await this.cleanUp(pathdir);
|
|
102
|
+
// eslint-disable-next-line no-console
|
|
103
|
+
console.log(error.message || error);
|
|
104
|
+
}
|
|
100
105
|
}
|
|
101
106
|
}
|
|
102
107
|
|
|
@@ -142,25 +147,27 @@ class StackCloneCommand extends Command {
|
|
|
142
147
|
const interrupt = ['SIGINT', 'SIGQUIT', 'SIGTERM'];
|
|
143
148
|
const exceptions = ['unhandledRejection', 'uncaughtException'];
|
|
144
149
|
|
|
145
|
-
const cleanUp = async (exitOrError
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
exitOrError
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
150
|
+
const cleanUp = async (exitOrError) => {
|
|
151
|
+
if (exitOrError) {
|
|
152
|
+
// eslint-disable-next-line no-console
|
|
153
|
+
console.log('\nCleaning up');
|
|
154
|
+
await this.cleanUp(pathDir)
|
|
155
|
+
// eslint-disable-next-line no-console
|
|
156
|
+
console.log('done');
|
|
157
|
+
// eslint-disable-next-line no-process-exit
|
|
158
|
+
|
|
159
|
+
if (exitOrError instanceof Promise) {
|
|
160
|
+
exitOrError.catch((error) => {
|
|
161
|
+
console.log((error && error.message) || '');
|
|
162
|
+
});
|
|
163
|
+
} else if (exitOrError && exitOrError.message) {
|
|
164
|
+
console.log(exitOrError.message);
|
|
165
|
+
} else if (exitOrError && exitOrError.errorMessage) {
|
|
166
|
+
console.log(exitOrError.message);
|
|
167
|
+
}
|
|
162
168
|
|
|
163
|
-
|
|
169
|
+
if (exitOrError === true) process.exit();
|
|
170
|
+
}
|
|
164
171
|
};
|
|
165
172
|
|
|
166
173
|
exceptions.forEach((event) => process.on(event, cleanUp));
|
|
@@ -231,6 +238,9 @@ b) Structure with content (all modules including entries & assets)
|
|
|
231
238
|
required: false,
|
|
232
239
|
default: 'disable',
|
|
233
240
|
}),
|
|
241
|
+
'master-locale': flags.string({
|
|
242
|
+
description: 'Master language for stack clone',
|
|
243
|
+
}),
|
|
234
244
|
};
|
|
235
245
|
|
|
236
246
|
StackCloneCommand.usage =
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const CloneCommand = function (execute, undo, params, parentContext) {
|
|
2
|
+
this.execute = execute.bind(parentContext);
|
|
3
|
+
this.undo = undo && undo.bind(parentContext);
|
|
4
|
+
this.params = params;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
const HandleOrgCommand = function (params, parentContext) {
|
|
8
|
+
return new CloneCommand(parentContext.handleOrgSelection, null, params, parentContext);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const HandleStackCommand = function (params, parentContext) {
|
|
12
|
+
return new CloneCommand(parentContext.handleStackSelection, parentContext.execute, params, parentContext);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const HandleBranchCommand = function (params, parentContext) {
|
|
16
|
+
return new CloneCommand(parentContext.handleBranchSelection, parentContext.execute, params, parentContext);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const HandleDestinationStackCommand = function (params, parentContext) {
|
|
20
|
+
return new CloneCommand(parentContext.handleStackSelection, parentContext.executeDestination, params, parentContext);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const HandleExportCommand = function (params, parentContext) {
|
|
24
|
+
return new CloneCommand(parentContext.cmdExport, null, params, parentContext);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const SetBranchCommand = function (params, parentContext) {
|
|
28
|
+
return new CloneCommand(parentContext.setBranch, null, params, parentContext);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const CreateNewStackCommand = function (params, parentContext) {
|
|
32
|
+
return new CloneCommand(parentContext.createNewStack, null, params, parentContext);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const CloneTypeSelectionCommand = function (params, parentContext) {
|
|
36
|
+
return new CloneCommand(parentContext.cloneTypeSelection, null, params, parentContext);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const Clone = function () {
|
|
40
|
+
const commands = [];
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
execute: async function (command) {
|
|
44
|
+
commands.push(command);
|
|
45
|
+
const result = await command.execute(command.params);
|
|
46
|
+
return result;
|
|
47
|
+
},
|
|
48
|
+
undo: async function () {
|
|
49
|
+
if (commands.length) {
|
|
50
|
+
const command = commands.pop();
|
|
51
|
+
command.undo && await command.undo(command.params);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
module.exports = {
|
|
58
|
+
HandleOrgCommand,
|
|
59
|
+
HandleStackCommand,
|
|
60
|
+
HandleBranchCommand,
|
|
61
|
+
HandleDestinationStackCommand,
|
|
62
|
+
HandleExportCommand,
|
|
63
|
+
SetBranchCommand,
|
|
64
|
+
CreateNewStackCommand,
|
|
65
|
+
CloneTypeSelectionCommand,
|
|
66
|
+
Clone,
|
|
67
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { EventEmitter } = require('events');
|
|
4
|
+
|
|
5
|
+
class CustomAbortSignal {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.eventEmitter = new EventEmitter();
|
|
8
|
+
this.onabort = null;
|
|
9
|
+
this.aborted = false;
|
|
10
|
+
}
|
|
11
|
+
toString() {
|
|
12
|
+
return '[object CustomAbortSignal]';
|
|
13
|
+
}
|
|
14
|
+
get [Symbol.toStringTag]() {
|
|
15
|
+
return 'CustomAbortSignal';
|
|
16
|
+
}
|
|
17
|
+
removeEventListener(name, handler) {
|
|
18
|
+
this.eventEmitter.removeListener(name, handler);
|
|
19
|
+
}
|
|
20
|
+
addEventListener(name, handler) {
|
|
21
|
+
this.eventEmitter.on(name, handler);
|
|
22
|
+
}
|
|
23
|
+
dispatchEvent(type) {
|
|
24
|
+
const event = { type, target: this };
|
|
25
|
+
const handlerName = `on${type}`;
|
|
26
|
+
|
|
27
|
+
if (typeof this[handlerName] === 'function') this[handlerName](event);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
class CustomAbortController {
|
|
32
|
+
constructor() {
|
|
33
|
+
this.signal = new CustomAbortSignal();
|
|
34
|
+
}
|
|
35
|
+
abort() {
|
|
36
|
+
if (this.signal.aborted) return;
|
|
37
|
+
|
|
38
|
+
this.signal.aborted = true;
|
|
39
|
+
this.signal.dispatchEvent('abort');
|
|
40
|
+
}
|
|
41
|
+
toString() {
|
|
42
|
+
return '[object CustomAbortController]';
|
|
43
|
+
}
|
|
44
|
+
get [Symbol.toStringTag]() {
|
|
45
|
+
return 'CustomAbortController';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = { CustomAbortController, CustomAbortSignal };
|
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
const ora = require('ora');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const inquirer = require('inquirer');
|
|
4
|
+
const rimraf = require('rimraf');
|
|
5
|
+
const chalk = require('chalk');
|
|
4
6
|
|
|
5
|
-
let sdkInstance = require('../../lib/util/contentstack-management-sdk');
|
|
6
7
|
let exportCmd = require('@contentstack/cli-cm-export');
|
|
7
8
|
let importCmd = require('@contentstack/cli-cm-import');
|
|
9
|
+
const { HttpClient, chooseLocalePrompt } = require('@contentstack/cli-utilities');
|
|
10
|
+
let sdkInstance = require('../../lib/util/contentstack-management-sdk');
|
|
11
|
+
const defaultConfig = require('@contentstack/cli-cm-export/src/config/default');
|
|
12
|
+
const { CustomAbortController } = require('./abort-controller');
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
HandleOrgCommand, HandleStackCommand, HandleDestinationStackCommand, HandleExportCommand,
|
|
16
|
+
SetBranchCommand, CreateNewStackCommand, CloneTypeSelectionCommand, Clone, HandleBranchCommand
|
|
17
|
+
} = require('../helpers/command-helpers');
|
|
18
|
+
|
|
8
19
|
let client = {};
|
|
9
20
|
let config;
|
|
21
|
+
let cloneCommand;
|
|
10
22
|
|
|
11
23
|
let stackCreationConfirmation = [
|
|
12
24
|
{
|
|
@@ -32,6 +44,7 @@ let structureList = [
|
|
|
32
44
|
'locales',
|
|
33
45
|
'environments',
|
|
34
46
|
'extensions',
|
|
47
|
+
'marketplace-apps',
|
|
35
48
|
'webhooks',
|
|
36
49
|
'global-fields',
|
|
37
50
|
'content-types',
|
|
@@ -44,9 +57,12 @@ class CloneHandler {
|
|
|
44
57
|
constructor(opt) {
|
|
45
58
|
config = opt;
|
|
46
59
|
client = sdkInstance.Client(config);
|
|
60
|
+
cloneCommand = new Clone();
|
|
61
|
+
this.pathDir = opt.pathDir;
|
|
62
|
+
process.stdin.setMaxListeners(50);
|
|
47
63
|
}
|
|
48
64
|
|
|
49
|
-
|
|
65
|
+
handleOrgSelection(options = {}) {
|
|
50
66
|
return new Promise(async (resolve, reject) => {
|
|
51
67
|
const { msg = '', isSource = true } = options || {};
|
|
52
68
|
const orgList = await this.getOrganizationChoices(msg).catch(reject);
|
|
@@ -65,113 +81,266 @@ class CloneHandler {
|
|
|
65
81
|
});
|
|
66
82
|
}
|
|
67
83
|
|
|
68
|
-
|
|
84
|
+
handleStackSelection(options = {}) {
|
|
85
|
+
let keyPressHandler;
|
|
69
86
|
return new Promise(async (resolve, reject) => {
|
|
70
|
-
|
|
71
|
-
|
|
87
|
+
try {
|
|
88
|
+
const { org = {}, msg = '', isSource = true, stackAbortController } = options || {}
|
|
89
|
+
|
|
90
|
+
keyPressHandler = async function (_ch, key) {
|
|
91
|
+
if (key.name === 'backspace') {
|
|
92
|
+
stackAbortController.abort();
|
|
93
|
+
console.clear();
|
|
94
|
+
process.stdin.removeListener('keypress', keyPressHandler);
|
|
95
|
+
await cloneCommand.undo();
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
process.stdin.addListener('keypress', keyPressHandler);
|
|
72
99
|
|
|
73
|
-
|
|
74
|
-
const selectedStack = await inquirer.prompt(stackList);
|
|
100
|
+
const stackList = await this.getStack(org, msg, isSource).catch(reject)
|
|
75
101
|
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
config.destinationStackName = selectedStack.stack;
|
|
83
|
-
}
|
|
102
|
+
if (stackList) {
|
|
103
|
+
const ui = new inquirer.ui.BottomBar();
|
|
104
|
+
// Use chalk to prettify the text.
|
|
105
|
+
ui.updateBottomBar(chalk.cyan('\nFor undo operation press backspace\n'));
|
|
106
|
+
|
|
107
|
+
const selectedStack = await inquirer.prompt(stackList);
|
|
84
108
|
|
|
85
|
-
|
|
109
|
+
if (stackAbortController.signal.aborted) {
|
|
110
|
+
return reject();
|
|
111
|
+
}
|
|
112
|
+
if (isSource) {
|
|
113
|
+
config.sourceStackName = selectedStack.stack;
|
|
114
|
+
master_locale = masterLocaleList[selectedStack.stack];
|
|
115
|
+
config.source_stack = stackUidList[selectedStack.stack];
|
|
116
|
+
} else {
|
|
117
|
+
config.target_stack = stackUidList[selectedStack.stack];
|
|
118
|
+
config.destinationStackName = selectedStack.stack;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
resolve(selectedStack)
|
|
122
|
+
}
|
|
123
|
+
} catch (error) {
|
|
124
|
+
return reject(error);
|
|
125
|
+
} finally {
|
|
126
|
+
if (keyPressHandler) {
|
|
127
|
+
process.stdin.removeListener('keypress', keyPressHandler);
|
|
128
|
+
}
|
|
86
129
|
}
|
|
87
130
|
});
|
|
88
131
|
}
|
|
89
132
|
|
|
90
|
-
|
|
133
|
+
handleBranchSelection = async (options) => {
|
|
134
|
+
const { api_key, isSource = true, returnBranch = false } = options
|
|
135
|
+
const baseUrl = defaultConfig.host.startsWith('http')
|
|
136
|
+
? defaultConfig.host
|
|
137
|
+
: `https://${defaultConfig.host}/v3`;
|
|
138
|
+
|
|
91
139
|
return new Promise(async (resolve, reject) => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
return new Promise(async (_resolve) => {
|
|
95
|
-
const org = await this.#handleOrgSelection({ msg: orgMsg, isSource }).catch((error) =>
|
|
96
|
-
reject(error.errorMessage),
|
|
97
|
-
);
|
|
140
|
+
try {
|
|
141
|
+
const headers = { api_key }
|
|
98
142
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
})
|
|
105
|
-
.then(_resolve)
|
|
106
|
-
.catch((error) => reject(error.errorMessage));
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
};
|
|
143
|
+
if (config.auth_token) {
|
|
144
|
+
headers['authtoken'] = config.auth_token
|
|
145
|
+
} else if (config.management_token) {
|
|
146
|
+
headers['authorization'] = config.management_token
|
|
147
|
+
}
|
|
110
148
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
);
|
|
117
|
-
}
|
|
149
|
+
// NOTE validate if source branch is exist
|
|
150
|
+
if (isSource && config.sourceStackBranch) {
|
|
151
|
+
await this.validateIfBranchExist(headers, true)
|
|
152
|
+
return resolve()
|
|
153
|
+
}
|
|
118
154
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
155
|
+
// NOTE Validate target branch is exist
|
|
156
|
+
if (!isSource && config.targetStackBranch) {
|
|
157
|
+
await this.validateIfBranchExist(headers, false)
|
|
158
|
+
return resolve()
|
|
159
|
+
}
|
|
122
160
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
161
|
+
const spinner = ora('Fetching Branches').start();
|
|
162
|
+
const result = await new HttpClient()
|
|
163
|
+
.headers(headers)
|
|
164
|
+
.get(`${baseUrl}/stacks/branches`)
|
|
165
|
+
.then(({ data: { branches } }) => branches)
|
|
166
|
+
|
|
167
|
+
const condition = (
|
|
168
|
+
result &&
|
|
169
|
+
Array.isArray(result) &&
|
|
170
|
+
result.length > 0
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
// NOTE if want to get only list of branches (Pass param -> returnBranch = true )
|
|
174
|
+
if (returnBranch) {
|
|
175
|
+
resolve(condition ? result : [])
|
|
176
|
+
} else {
|
|
177
|
+
// NOTE list options to use to select branch
|
|
178
|
+
if (condition) {
|
|
179
|
+
spinner.succeed('Fetched Branches');
|
|
180
|
+
const { branch } = await inquirer.prompt({
|
|
181
|
+
type: 'list',
|
|
182
|
+
name: 'branch',
|
|
183
|
+
message: 'Choose a branch',
|
|
184
|
+
choices: result.map(row => row.uid),
|
|
185
|
+
});
|
|
126
186
|
|
|
127
|
-
if (
|
|
128
|
-
config.sourceStackBranch =
|
|
187
|
+
if (isSource) {
|
|
188
|
+
config.sourceStackBranch = branch
|
|
189
|
+
} else {
|
|
190
|
+
config.targetStackBranch = branch
|
|
129
191
|
}
|
|
130
|
-
}
|
|
192
|
+
} else {
|
|
193
|
+
spinner.succeed('No branches found.!');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
resolve()
|
|
131
197
|
}
|
|
198
|
+
} catch (e) {
|
|
199
|
+
spinner.fail();
|
|
200
|
+
console.log(e && e.message)
|
|
201
|
+
resolve()
|
|
202
|
+
}
|
|
203
|
+
})
|
|
204
|
+
}
|
|
132
205
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
206
|
+
async validateIfBranchExist(headers, isSource) {
|
|
207
|
+
const branch = isSource ? config.sourceStackBranch : config.targetStackBranch
|
|
208
|
+
const spinner = ora(`Validation if ${isSource ? 'source' : 'target'} branch exist.!`).start();
|
|
209
|
+
const isBranchExist = await HttpClient.create()
|
|
210
|
+
.headers(headers)
|
|
211
|
+
.get(`https://${config.host}/v3/stacks/branches/${branch}`)
|
|
212
|
+
.then(({ data }) => data);
|
|
213
|
+
|
|
214
|
+
const completeSpinner = (msg, method = 'succeed') => {
|
|
215
|
+
spinner[method](msg)
|
|
216
|
+
spinner.stop()
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (isBranchExist && typeof isBranchExist === 'object' && typeof isBranchExist.branch === 'object') {
|
|
220
|
+
completeSpinner(`${isSource ? 'Source' : 'Target'} branch verified.!`)
|
|
221
|
+
} else {
|
|
222
|
+
completeSpinner(`${isSource ? 'Source' : 'Target'} branch not found.!`, 'fail')
|
|
223
|
+
process.exit()
|
|
224
|
+
}
|
|
225
|
+
}
|
|
136
226
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
227
|
+
execute() {
|
|
228
|
+
return new Promise(async (resolve, reject) => {
|
|
229
|
+
let stackAbortController;
|
|
230
|
+
|
|
231
|
+
try {
|
|
232
|
+
if (!config.source_stack) {
|
|
233
|
+
const orgMsg = 'Choose an organization where your source stack exists:';
|
|
234
|
+
const stackMsg = 'Select the source stack';
|
|
140
235
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
236
|
+
stackAbortController = new CustomAbortController();
|
|
237
|
+
|
|
238
|
+
const org = await cloneCommand.execute(new HandleOrgCommand({ msg: orgMsg, isSource: true }, this));
|
|
239
|
+
if (org) {
|
|
240
|
+
const sourceStack = await cloneCommand.execute(new HandleStackCommand({ org, isSource: true, msg: stackMsg, stackAbortController }, this));
|
|
241
|
+
|
|
242
|
+
if (config.source_stack) {
|
|
243
|
+
if (!(config.master_locale && config.master_locale.code)) {
|
|
244
|
+
|
|
245
|
+
const res = await chooseLocalePrompt(client.stack({ api_key: config.source_stack }), 'Choose Master Locale', master_locale)
|
|
246
|
+
master_locale = res.code
|
|
247
|
+
config.master_locale = res
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
master_locale = config.master_locale.code
|
|
251
|
+
}
|
|
252
|
+
await cloneCommand.execute(
|
|
253
|
+
new HandleBranchCommand({ api_key: config.source_stack }, this)
|
|
147
254
|
);
|
|
148
255
|
}
|
|
149
256
|
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
.then(resolve)
|
|
153
|
-
.catch((error) => reject(error.errorMessage));
|
|
257
|
+
if (stackAbortController.signal.aborted) {
|
|
258
|
+
return reject();
|
|
154
259
|
}
|
|
260
|
+
stackName.default = config.stackName || `Copy of ${sourceStack.stack || config.source_alias}`;
|
|
155
261
|
} else {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
262
|
+
return reject('Org not found.');
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const exportRes = await cloneCommand.execute(new HandleExportCommand(null, this));
|
|
266
|
+
await cloneCommand.execute(new SetBranchCommand(null, this));
|
|
267
|
+
|
|
268
|
+
if (exportRes) {
|
|
269
|
+
this.executeDestination().catch(() => { reject(); });
|
|
270
|
+
}
|
|
271
|
+
return resolve();
|
|
272
|
+
} catch (error) {
|
|
273
|
+
return reject(error);
|
|
274
|
+
} finally {
|
|
275
|
+
if (stackAbortController) {
|
|
276
|
+
stackAbortController.abort();
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
async executeDestination() {
|
|
283
|
+
return new Promise(async (resolve, reject) => {
|
|
284
|
+
let stackAbortController;
|
|
285
|
+
try {
|
|
286
|
+
stackAbortController = new CustomAbortController();
|
|
287
|
+
|
|
288
|
+
let canCreateStack = false;
|
|
289
|
+
|
|
290
|
+
if (!config.target_stack) {
|
|
291
|
+
canCreateStack = await inquirer.prompt(stackCreationConfirmation);
|
|
292
|
+
}
|
|
164
293
|
|
|
165
|
-
|
|
166
|
-
|
|
294
|
+
if (!canCreateStack.stackCreate) {
|
|
295
|
+
if (!config.target_stack) {
|
|
296
|
+
const orgMsg = 'Choose an organization where the destination stack exists: ';
|
|
297
|
+
const org = await cloneCommand.execute(new HandleOrgCommand({ msg: orgMsg }, this));
|
|
298
|
+
|
|
299
|
+
if (org) {
|
|
300
|
+
const stackMsg = 'Choose the destination stack:';
|
|
301
|
+
await cloneCommand.execute(new HandleDestinationStackCommand({ org, msg: stackMsg, stackAbortController, isSource: false }, this));
|
|
167
302
|
}
|
|
168
303
|
}
|
|
304
|
+
|
|
305
|
+
// NOTE GET list of branches if branches enabled
|
|
306
|
+
if (config.target_stack) {
|
|
307
|
+
await cloneCommand.execute(new HandleBranchCommand({ isSource: false, api_key: config.target_stack }, this));
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
const destinationOrg = await this.handleOrgSelection({ isSource: false, msg: 'Choose an organization where you want to create a stack: ' });
|
|
311
|
+
const orgUid = orgUidList[destinationOrg.Organization];
|
|
312
|
+
await cloneCommand.execute(new CreateNewStackCommand(orgUid, this));
|
|
313
|
+
}
|
|
314
|
+
await cloneCommand.execute(new CloneTypeSelectionCommand(null, this));
|
|
315
|
+
return resolve();
|
|
316
|
+
} catch (error) {
|
|
317
|
+
reject(error);
|
|
318
|
+
} finally {
|
|
319
|
+
// If not aborted and ran successfully
|
|
320
|
+
if (!stackAbortController.signal.aborted) {
|
|
321
|
+
// Call clean dir.
|
|
322
|
+
rimraf(this.pathDir, function () {
|
|
323
|
+
// eslint-disable-next-line no-console
|
|
324
|
+
console.log('Stack cloning process have been completed successfully');
|
|
325
|
+
});
|
|
169
326
|
}
|
|
170
327
|
}
|
|
171
|
-
})
|
|
328
|
+
})
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
async setBranch() {
|
|
332
|
+
if (!config.sourceStackBranch) {
|
|
333
|
+
try {
|
|
334
|
+
const branches = await client.stack({ api_key: config.source_stack }).branch().query().find();
|
|
335
|
+
|
|
336
|
+
if (branches && branches.items && branches.items.length) {
|
|
337
|
+
config.sourceStackBranch = 'main';
|
|
338
|
+
}
|
|
339
|
+
} catch (_error) { }
|
|
340
|
+
}
|
|
172
341
|
}
|
|
173
342
|
|
|
174
|
-
|
|
343
|
+
async getOrganizationChoices(orgMessage) {
|
|
175
344
|
let orgChoice = {
|
|
176
345
|
type: 'list',
|
|
177
346
|
name: 'Organization',
|
|
@@ -183,9 +352,9 @@ class CloneHandler {
|
|
|
183
352
|
try {
|
|
184
353
|
let organizations = await client.organization().fetchAll({ limit: 100 });
|
|
185
354
|
spinner.succeed('Fetched Organization');
|
|
186
|
-
for (
|
|
187
|
-
orgUidList[
|
|
188
|
-
orgChoice.choices.push(
|
|
355
|
+
for (const element of organizations.items) {
|
|
356
|
+
orgUidList[element.name] = element.uid;
|
|
357
|
+
orgChoice.choices.push(element.name);
|
|
189
358
|
}
|
|
190
359
|
return resolve(orgChoice);
|
|
191
360
|
} catch (e) {
|
|
@@ -195,7 +364,7 @@ class CloneHandler {
|
|
|
195
364
|
});
|
|
196
365
|
};
|
|
197
366
|
|
|
198
|
-
|
|
367
|
+
async getStack(answer, stkMessage) {
|
|
199
368
|
return new Promise(async (resolve, reject) => {
|
|
200
369
|
let stackChoice = {
|
|
201
370
|
type: 'list',
|
|
@@ -209,10 +378,10 @@ class CloneHandler {
|
|
|
209
378
|
const stackList = client.stack().query({ organization_uid }).find();
|
|
210
379
|
stackList
|
|
211
380
|
.then((stacklist) => {
|
|
212
|
-
for (
|
|
213
|
-
stackUidList[
|
|
214
|
-
masterLocaleList[
|
|
215
|
-
stackChoice.choices.push(
|
|
381
|
+
for (const element of stacklist.items) {
|
|
382
|
+
stackUidList[element.name] = element.api_key;
|
|
383
|
+
masterLocaleList[element.name] = element.master_locale;
|
|
384
|
+
stackChoice.choices.push(element.name);
|
|
216
385
|
}
|
|
217
386
|
spinner.succeed('Fetched stack');
|
|
218
387
|
return resolve(stackChoice);
|
|
@@ -250,7 +419,7 @@ class CloneHandler {
|
|
|
250
419
|
})
|
|
251
420
|
.catch((error) => {
|
|
252
421
|
spinner.fail();
|
|
253
|
-
return reject(error);
|
|
422
|
+
return reject(error.errorMessage + ' Contact the Organization owner for Stack Creation access.');
|
|
254
423
|
});
|
|
255
424
|
});
|
|
256
425
|
}
|