@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.0.0",
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.0.0",
9
- "@contentstack/cli-cm-import": "^1.0.0",
10
- "@contentstack/cli-command": "^1.0.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
- await cloneHandler.start();
75
- let successMessage = 'Stack cloning process have been completed successfully';
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
- await this.cleanUp(pathdir);
98
- // eslint-disable-next-line no-console
99
- console.log(error.message || error);
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 = null) => {
146
- // eslint-disable-next-line no-console
147
- console.log('\nCleaning up');
148
- await this.cleanUp(pathDir);
149
- // eslint-disable-next-line no-console
150
- console.log('done');
151
- // eslint-disable-next-line no-process-exit
152
-
153
- if (exitOrError instanceof Promise) {
154
- exitOrError.catch((error) => {
155
- console.log((error && error.message) || '');
156
- });
157
- } else if (exitOrError && exitOrError.message) {
158
- console.log(exitOrError.message);
159
- } else if (exitOrError && exitOrError.errorMessage) {
160
- console.log(exitOrError.message);
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
- if (exitOrError === true) process.exit();
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
- #handleOrgSelection(options = {}) {
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
- #handleStackSelection(options = {}) {
84
+ handleStackSelection(options = {}) {
85
+ let keyPressHandler;
69
86
  return new Promise(async (resolve, reject) => {
70
- const { org = {}, msg = '', isSource = true } = options || {};
71
- const stackList = await this.getStack(org, msg, isSource).catch(reject);
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
- if (stackList) {
74
- const selectedStack = await inquirer.prompt(stackList);
100
+ const stackList = await this.getStack(org, msg, isSource).catch(reject)
75
101
 
76
- if (isSource) {
77
- config.sourceStackName = selectedStack.stack;
78
- master_locale = masterLocaleList[selectedStack.stack];
79
- config.source_stack = stackUidList[selectedStack.stack];
80
- } else {
81
- config.target_stack = stackUidList[selectedStack.stack];
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
- resolve(selectedStack);
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
- start() {
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
- let sourceStack = {};
93
- const handleOrgAndStackSelection = (orgMsg, stackMsg, isSource = true) => {
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
- if (org) {
100
- await this.#handleStackSelection({
101
- org,
102
- isSource,
103
- msg: stackMsg,
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
- if (!config.source_stack) {
112
- // NOTE Export section
113
- sourceStack = await handleOrgAndStackSelection(
114
- 'Choose an organization where your source stack exists:',
115
- 'Select the source stack',
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
- if (config.source_stack) {
120
- stackName.default = config.stackName || `Copy of ${sourceStack.stack || config.source_alias}`;
121
- const exportRes = await this.cmdExport().catch(reject);
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
- if (!config.sourceStackBranch) {
124
- try {
125
- const branches = await client.stack({ api_key: config.source_stack }).branch().query().find();
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 (branches && branches.items && branches.items.length) {
128
- config.sourceStackBranch = 'main';
187
+ if (isSource) {
188
+ config.sourceStackBranch = branch
189
+ } else {
190
+ config.targetStackBranch = branch
129
191
  }
130
- } catch (_error) {}
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
- // NOTE Import section
134
- if (exportRes) {
135
- let canCreateStack = false;
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
- if (!config.target_stack) {
138
- canCreateStack = await inquirer.prompt(stackCreationConfirmation);
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
- if (canCreateStack.stackCreate !== true) {
142
- if (!config.target_stack) {
143
- await handleOrgAndStackSelection(
144
- 'Choose an organization where the destination stack exists: ',
145
- 'Choose the destination stack:',
146
- false,
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 (config.target_stack) {
151
- this.cloneTypeSelection()
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
- const destinationOrg = await this.#handleOrgSelection({
157
- isSource: false,
158
- msg: 'Choose an organization where you want to create a stack: ',
159
- }).catch((error) => reject(error.errorMessage));
160
- const orgUid = orgUidList[destinationOrg.Organization];
161
- await this.createNewStack(orgUid).catch((error) => {
162
- return reject(error.errorMessage + ' Contact the Organization owner for Stack Creation access.');
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
- if (config.target_stack) {
166
- this.cloneTypeSelection().then(resolve).catch(reject);
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
- getOrganizationChoices = async (orgMessage) => {
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 (let i = 0; i < organizations.items.length; i++) {
187
- orgUidList[organizations.items[i].name] = organizations.items[i].uid;
188
- orgChoice.choices.push(organizations.items[i].name);
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
- getStack = async (answer, stkMessage) => {
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 (let j = 0; j < stacklist.items.length; j++) {
213
- stackUidList[stacklist.items[j].name] = stacklist.items[j].api_key;
214
- masterLocaleList[stacklist.items[j].name] = stacklist.items[j].master_locale;
215
- stackChoice.choices.push(stacklist.items[j].name);
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
  }