@adobe/aio-cli-plugin-api-mesh 1.3.0 → 2.0.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.
@@ -84,10 +84,10 @@ describe('update command tests', () => {
84
84
  await expect(runResult).rejects.toMatchInlineSnapshot(
85
85
  `[Error: Unable to update. No mesh found for Org(1234) -> Project(5678) -> Workspace(123456789). Please check the details and try again.]`,
86
86
  );
87
- expect(logSpy.mock.calls).toMatchInlineSnapshot(`Array []`);
87
+ expect(logSpy.mock.calls).toMatchInlineSnapshot(`[]`);
88
88
  expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
89
- Array [
90
- Array [
89
+ [
90
+ [
91
91
  "Unable to update. No mesh found for Org(1234) -> Project(5678) -> Workspace(123456789). Please check the details and try again.",
92
92
  ],
93
93
  ]
@@ -101,10 +101,10 @@ describe('update command tests', () => {
101
101
  await expect(runResult).rejects.toMatchInlineSnapshot(
102
102
  `[Error: Unable to get mesh ID. Please check the details and try again. RequestId: dummy_request_id]`,
103
103
  );
104
- expect(logSpy.mock.calls).toMatchInlineSnapshot(`Array []`);
104
+ expect(logSpy.mock.calls).toMatchInlineSnapshot(`[]`);
105
105
  expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
106
- Array [
107
- Array [
106
+ [
107
+ [
108
108
  "Unable to get mesh ID. Please check the details and try again. RequestId: dummy_request_id",
109
109
  ],
110
110
  ]
@@ -124,10 +124,10 @@ describe('update command tests', () => {
124
124
  await expect(runResult).rejects.toEqual(
125
125
  new Error('Missing required args. Run aio api-mesh update --help for more info.'),
126
126
  );
127
- expect(logSpy.mock.calls).toMatchInlineSnapshot(`Array []`);
127
+ expect(logSpy.mock.calls).toMatchInlineSnapshot(`[]`);
128
128
  expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
129
- Array [
130
- Array [
129
+ [
130
+ [
131
131
  "Missing required args. Run aio api-mesh update --help for more info.",
132
132
  ],
133
133
  ]
@@ -144,15 +144,15 @@ describe('update command tests', () => {
144
144
  ),
145
145
  );
146
146
  expect(logSpy.mock.calls).toMatchInlineSnapshot(`
147
- Array [
148
- Array [
147
+ [
148
+ [
149
149
  "File not found",
150
150
  ],
151
151
  ]
152
152
  `);
153
153
  expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
154
- Array [
155
- Array [
154
+ [
155
+ [
156
156
  "Unable to read the mesh configuration file provided. Please check the file and try again.",
157
157
  ],
158
158
  ]
@@ -166,13 +166,13 @@ describe('update command tests', () => {
166
166
 
167
167
  expect(runResult).toMatchInlineSnapshot(`"Update cancelled"`);
168
168
  expect(logSpy.mock.calls).toMatchInlineSnapshot(`
169
- Array [
170
- Array [
169
+ [
170
+ [
171
171
  "Update cancelled",
172
172
  ],
173
173
  ]
174
174
  `);
175
- expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`Array []`);
175
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`[]`);
176
176
  });
177
177
 
178
178
  test('should fail if updateMesh method failed', async () => {
@@ -186,15 +186,15 @@ describe('update command tests', () => {
186
186
  ),
187
187
  );
188
188
  expect(logSpy.mock.calls).toMatchInlineSnapshot(`
189
- Array [
190
- Array [
189
+ [
190
+ [
191
191
  "dummy_error",
192
192
  ],
193
193
  ]
194
194
  `);
195
195
  expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
196
- Array [
197
- Array [
196
+ [
197
+ [
198
198
  "Unable to update the mesh. Please check the mesh configuration file and try again. If the error persists please contact support. RequestId: dummy_request_id",
199
199
  ],
200
200
  ]
@@ -205,7 +205,7 @@ describe('update command tests', () => {
205
205
  const runResult = await UpdateCommand.run();
206
206
 
207
207
  expect(runResult).toMatchInlineSnapshot(`
208
- Object {
208
+ {
209
209
  "status": "success",
210
210
  }
211
211
  `);
@@ -214,14 +214,26 @@ describe('update command tests', () => {
214
214
  ignoreCache: true,
215
215
  });
216
216
  expect(logSpy.mock.calls).toMatchInlineSnapshot(`
217
- Array [
218
- Array [
219
- "Successfully updated the mesh with the id: %s",
217
+ [
218
+ [
219
+ "******************************************************************************************************",
220
+ ],
221
+ [
222
+ "Your mesh is being provisioned. Wait a few minutes before checking the status of your mesh %s",
220
223
  "mesh_id",
221
224
  ],
225
+ [
226
+ "To check the status of your mesh, run:",
227
+ ],
228
+ [
229
+ "aio api-mesh:status",
230
+ ],
231
+ [
232
+ "******************************************************************************************************",
233
+ ],
222
234
  ]
223
235
  `);
224
- expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`Array []`);
236
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`[]`);
225
237
  });
226
238
 
227
239
  test('should pass with valid args and ignoreCache flag', async () => {
@@ -236,7 +248,7 @@ describe('update command tests', () => {
236
248
  const runResult = await UpdateCommand.run();
237
249
 
238
250
  expect(runResult).toMatchInlineSnapshot(`
239
- Object {
251
+ {
240
252
  "status": "success",
241
253
  }
242
254
  `);
@@ -245,14 +257,26 @@ describe('update command tests', () => {
245
257
  ignoreCache: true,
246
258
  });
247
259
  expect(logSpy.mock.calls).toMatchInlineSnapshot(`
248
- Array [
249
- Array [
250
- "Successfully updated the mesh with the id: %s",
260
+ [
261
+ [
262
+ "******************************************************************************************************",
263
+ ],
264
+ [
265
+ "Your mesh is being provisioned. Wait a few minutes before checking the status of your mesh %s",
251
266
  "mesh_id",
252
267
  ],
268
+ [
269
+ "To check the status of your mesh, run:",
270
+ ],
271
+ [
272
+ "aio api-mesh:status",
273
+ ],
274
+ [
275
+ "******************************************************************************************************",
276
+ ],
253
277
  ]
254
278
  `);
255
- expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`Array []`);
279
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`[]`);
256
280
  });
257
281
 
258
282
  test('should pass with valid args if autoConfirmAction flag is set', async () => {
@@ -267,7 +291,7 @@ describe('update command tests', () => {
267
291
  const runResult = await UpdateCommand.run();
268
292
 
269
293
  expect(runResult).toMatchInlineSnapshot(`
270
- Object {
294
+ {
271
295
  "status": "success",
272
296
  }
273
297
  `);
@@ -277,13 +301,25 @@ describe('update command tests', () => {
277
301
  ignoreCache: true,
278
302
  });
279
303
  expect(logSpy.mock.calls).toMatchInlineSnapshot(`
280
- Array [
281
- Array [
282
- "Successfully updated the mesh with the id: %s",
304
+ [
305
+ [
306
+ "******************************************************************************************************",
307
+ ],
308
+ [
309
+ "Your mesh is being provisioned. Wait a few minutes before checking the status of your mesh %s",
283
310
  "mesh_id",
284
311
  ],
312
+ [
313
+ "To check the status of your mesh, run:",
314
+ ],
315
+ [
316
+ "aio api-mesh:status",
317
+ ],
318
+ [
319
+ "******************************************************************************************************",
320
+ ],
285
321
  ]
286
322
  `);
287
- expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`Array []`);
323
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`[]`);
288
324
  });
289
325
  });
@@ -9,13 +9,13 @@ OF ANY KIND, either express or implied. See the License for the specific languag
9
9
  governing permissions and limitations under the License.
10
10
  */
11
11
 
12
- const { Command } = require('@oclif/command');
12
+ const { Command } = require('@oclif/core');
13
13
  const { readFile } = require('fs/promises');
14
14
 
15
15
  const { initSdk, initRequestId, promptConfirm } = require('../../helpers');
16
16
  const logger = require('../../classes/logger');
17
17
  const CONSTANTS = require('../../constants');
18
- const { ignoreCacheFlag, autoConfirmActionFlag } = require('../../utils');
18
+ const { ignoreCacheFlag, autoConfirmActionFlag, jsonFlag } = require('../../utils');
19
19
  const {
20
20
  createMesh,
21
21
  createAPIMeshCredentials,
@@ -31,8 +31,11 @@ class CreateCommand extends Command {
31
31
  static flags = {
32
32
  ignoreCache: ignoreCacheFlag,
33
33
  autoConfirmAction: autoConfirmActionFlag,
34
+ json: jsonFlag,
34
35
  };
35
36
 
37
+ static enableJsonFlag = true;
38
+
36
39
  async run() {
37
40
  await initRequestId();
38
41
 
@@ -78,8 +81,19 @@ class CreateCommand extends Command {
78
81
  let sdkList = [];
79
82
 
80
83
  if (mesh) {
81
- this.log('Successfully created mesh %s', mesh.meshId);
82
- this.log(JSON.stringify(mesh, null, 2));
84
+ this.log(
85
+ '******************************************************************************************************',
86
+ );
87
+ this.log(
88
+ 'Your mesh is being provisioned. Wait a few minutes before checking the status of your mesh %s',
89
+ mesh.meshId,
90
+ );
91
+ this.log('To check the status of your mesh, run:');
92
+ this.log('aio api-mesh:status');
93
+ this.log(
94
+ '******************************************************************************************************',
95
+ );
96
+
83
97
  // create API key credential
84
98
  const adobeIdIntegrationsForWorkspace = await createAPIMeshCredentials(
85
99
  imsOrgId,
@@ -116,7 +130,8 @@ class CreateCommand extends Command {
116
130
  } else {
117
131
  this.log('Unable to create API Key');
118
132
  }
119
-
133
+ // Do not remove or rename return values.
134
+ // Template adobe/generator-app-api-mesh relies on "mesh" & "adobeIdIntegrationsForWorkspace" obj structure
120
135
  return {
121
136
  adobeIdIntegrationsForWorkspace,
122
137
  sdkList,
@@ -62,7 +62,7 @@ class DescribeCommand extends Command {
62
62
 
63
63
  return meshDetails;
64
64
  } else {
65
- this.error(
65
+ logger.error(
66
66
  `Unable to get mesh details. Please check the details and try again. RequestId: ${global.requestId}`,
67
67
  { exit: false },
68
68
  );
@@ -70,7 +70,7 @@ class GetCommand extends Command {
70
70
 
71
71
  return mesh;
72
72
  } else {
73
- this.error(
73
+ logger.error(
74
74
  `Unable to get mesh with the ID ${meshId}. Please check the mesh ID and try again. RequestId: ${global.requestId}`,
75
75
  { exit: false },
76
76
  );
@@ -41,4 +41,4 @@
41
41
  }
42
42
  ]
43
43
  }
44
- }
44
+ }
@@ -41,4 +41,4 @@
41
41
  }
42
42
  ]
43
43
  }
44
- }
44
+ }
@@ -12,10 +12,10 @@ governing permissions and limitations under the License.
12
12
 
13
13
  const mockMetadataFixture = require('../__fixtures__/connectors-metadata.json');
14
14
  const mockAdapter = require('source-registry-storage-adapter');
15
- const { promptConfirm } = require('../../../../helpers');
16
- const GetCommand = require('../get');
15
+ const { promptConfirm, promptMultiselect } = require('../../../../helpers');
17
16
  const { CliUx } = require('@oclif/core');
18
17
  const DiscoverCommand = require('../discover');
18
+ const InstallCommand = require('../install');
19
19
  jest.mock('source-registry-storage-adapter');
20
20
  jest.mock('../../../../helpers');
21
21
  jest.mock('../get');
@@ -37,22 +37,23 @@ describe('source:discover command tests', () => {
37
37
  expect(DiscoverCommand.description).toMatchInlineSnapshot(
38
38
  `"Return the list of avaliable sources"`,
39
39
  );
40
- expect(DiscoverCommand.aliases).toMatchInlineSnapshot(`Array []`);
40
+ expect(DiscoverCommand.aliases).toMatchInlineSnapshot(`[]`);
41
41
  });
42
42
  test('Check table render is executed', async () => {
43
43
  await DiscoverCommand.run([]);
44
44
  expect(CliUx.Table.table).toHaveBeenCalledTimes(1);
45
45
  });
46
- test('Check that "source:get -m" command is called', async () => {
47
- GetCommand.run = jest.fn().mockImplementation(() => 'source:get -m');
46
+ test('Check that "source:install" command is called', async () => {
47
+ InstallCommand.run = jest.fn().mockImplementation(() => 'source:install');
48
48
  promptConfirm.mockResolvedValue(true);
49
+ promptMultiselect.mockResolvedValue([mockMetadataFixture['test-01']]);
49
50
  await DiscoverCommand.run([]);
50
- expect(GetCommand.run).toHaveBeenCalledTimes(1);
51
+ expect(InstallCommand.run).toHaveBeenCalledTimes(1);
51
52
  });
52
- test('Check that "source:get -m" command is not called', async () => {
53
- GetCommand.run = jest.fn().mockImplementation(() => 'source:get -m');
53
+ test('Check that "source:install" command is not called', async () => {
54
+ InstallCommand.run = jest.fn().mockImplementation(() => 'source:install');
54
55
  promptConfirm.mockResolvedValue(false);
55
56
  await DiscoverCommand.run([]);
56
- expect(GetCommand.run).toHaveBeenCalledTimes(0);
57
+ expect(InstallCommand.run).toHaveBeenCalledTimes(0);
57
58
  });
58
59
  });
@@ -30,6 +30,12 @@ const expectedResultForSuccessScenarios = JSON.stringify(
30
30
  null,
31
31
  4,
32
32
  );
33
+ const normalizeAssertString = str => {
34
+ return str
35
+ .replace(/[\r\t]/gm, '')
36
+ .replace(/[\r\n]/gm, '')
37
+ .replace(/ +/g, ' ');
38
+ };
33
39
  mockAdapter.mockImplementation(() => ({
34
40
  get: jest
35
41
  .fn()
@@ -53,40 +59,48 @@ describe('source:get command tests', () => {
53
59
  `"Command returns the content of a specific source."`,
54
60
  );
55
61
  expect(GetCommand.flags).toMatchInlineSnapshot(`
56
- Object {
57
- "multiple": Object {
62
+ {
63
+ "confirm": {
64
+ "allowNo": false,
65
+ "char": "c",
66
+ "default": false,
67
+ "description": "Auto confirm print action prompt. CLI will not check ask user to print source.",
68
+ "parse": [Function],
69
+ "type": "boolean",
70
+ },
71
+ "multiple": {
58
72
  "allowNo": false,
59
73
  "char": "m",
60
74
  "description": "Select multiple sources",
61
- "exclusive": Array [
75
+ "exclusive": [
62
76
  "name",
63
77
  ],
64
78
  "parse": [Function],
65
79
  "type": "boolean",
66
80
  },
67
- "source": Object {
81
+ "source": {
68
82
  "char": "s",
69
83
  "description": "Source name",
70
- "input": Array [],
84
+ "input": [],
71
85
  "multiple": true,
72
86
  "parse": [Function],
73
87
  "type": "option",
74
88
  },
75
89
  }
76
90
  `);
77
- expect(GetCommand.aliases).toMatchInlineSnapshot(`Array []`);
91
+ expect(GetCommand.aliases).toMatchInlineSnapshot(`[]`);
78
92
  });
79
93
  test('Check executing without parameters', async () => {
80
94
  await GetCommand.run([]).catch(err => {
81
- expect(err.message).toEqual(`The "aio api-mesh:source:get" command requires additional parameters` +
82
- `\nUse "aio api-mesh:source:get --help" to see parameters information.`)
95
+ expect(normalizeAssertString(err.message)).toEqual(
96
+ normalizeAssertString(
97
+ `Something went wrong with "get" command. Please try again later.` +
98
+ `Error: \nThe "aio api-mesh:source:get" command requires additional parameters` +
99
+ `Use "aio api-mesh:source:get --help" to see parameters information.`,
100
+ ),
101
+ );
83
102
  });
84
103
  });
85
- test('Check executing success with multiple, copied to clipboard and logged to console', async () => {
86
- await GetCommand.run(['-m']);
87
- expect(ncp.readSync()).toEqual(expectedResultForSuccessScenarios);
88
- expect(logSpy.mock.calls.pop()[0]).toEqual(expectedResultForSuccessScenarios);
89
- });
90
104
  test('Check executing success with provided name and version, copied to clipboard and logged to console', async () => {
91
105
  await GetCommand.run(['-s=test-01@0.0.1', '-s=test-02@0.0.1']);
92
106
  expect(ncp.readSync()).toEqual(expectedResultForSuccessScenarios);
@@ -100,23 +114,15 @@ describe('source:get command tests', () => {
100
114
  test('Check executing failed due to requested source does not exist', async () => {
101
115
  const name = 'test-99';
102
116
  await GetCommand.run([`-s=${name}`]).catch(err => {
103
- expect(err.message).toEqual(
104
- chalk.red(
105
- `The source with the name "${name}" doesn't exist.` +
106
- `\nUse "aio api-mesh:source:discover" command to see avaliable sources.`,
107
- ),
108
- );
117
+ expect(err.message).toContain(chalk.red(`The source with the name "test-99" doesn't exist.`));
109
118
  });
110
119
  });
111
120
  test('Check executing failed due to requested version does not exist', async () => {
112
121
  const name = 'test-01';
113
122
  const version = '1.1.1';
114
123
  await GetCommand.run([`-s=${name}@${version}`]).catch(err => {
115
- expect(err.message).toEqual(
116
- chalk.red(
117
- `The version "${version}" for source name "${name}" doesn't exist.` +
118
- `\nUse "aio api-mesh:source:discover" command to see avaliable source versions.`,
119
- ),
124
+ expect(err.message).toContain(
125
+ chalk.red(`The version \"1.1.1\" for source name \"test-01\" doesn't exist.`),
120
126
  );
121
127
  });
122
128
  });
@@ -11,11 +11,10 @@ governing permissions and limitations under the License.
11
11
  */
12
12
 
13
13
  const mockMetadataFixture = require('../__fixtures__/connectors-metadata.json');
14
- const mockSourceTest01v1Fixture = require('../__fixtures__/0.0.1-test-01.json');
15
- const mockSourceTest02v1Fixture = require('../__fixtures__/0.0.1-test-02.json');
16
14
  const mockSourceTest03v1Fixture = require('../__fixtures__/0.0.1-test-03.json');
17
15
  const mockAdapter = require('source-registry-storage-adapter');
18
16
  const chalk = require('chalk');
17
+ const path = require('path');
19
18
  const { initSdk, initRequestId, promptInput } = require('../../../../helpers');
20
19
  const mockSources = { '0.0.1-test-03': mockSourceTest03v1Fixture };
21
20
  jest.mock('source-registry-storage-adapter');
@@ -50,8 +49,16 @@ describe('source:install command tests', () => {
50
49
  `"Command to install the source to your API mesh."`,
51
50
  );
52
51
  expect(InstallCommand.flags).toMatchInlineSnapshot(`
53
- Object {
54
- "ignoreCache": Object {
52
+ {
53
+ "confirm": {
54
+ "allowNo": false,
55
+ "char": "c",
56
+ "default": false,
57
+ "description": "Auto confirm override action prompt. CLI will not check ask user to override source.",
58
+ "parse": [Function],
59
+ "type": "boolean",
60
+ },
61
+ "ignoreCache": {
55
62
  "allowNo": false,
56
63
  "char": "i",
57
64
  "default": false,
@@ -59,25 +66,33 @@ describe('source:install command tests', () => {
59
66
  "parse": [Function],
60
67
  "type": "boolean",
61
68
  },
62
- "variable": Object {
69
+ "source": {
70
+ "char": "s",
71
+ "description": "Source name",
72
+ "input": [],
73
+ "multiple": true,
74
+ "parse": [Function],
75
+ "type": "option",
76
+ },
77
+ "variable": {
63
78
  "char": "v",
64
79
  "description": "Variables required for the source",
65
- "input": Array [],
80
+ "input": [],
66
81
  "multiple": true,
67
82
  "parse": [Function],
68
83
  "type": "option",
69
84
  },
70
- "variable-file": Object {
85
+ "variable-file": {
71
86
  "char": "f",
72
87
  "description": "Variables file path",
73
- "input": Array [],
88
+ "input": [],
74
89
  "multiple": false,
75
90
  "parse": [Function],
76
91
  "type": "option",
77
92
  },
78
93
  }
79
94
  `);
80
- expect(InstallCommand.aliases).toMatchInlineSnapshot(`Array []`);
95
+ expect(InstallCommand.aliases).toMatchInlineSnapshot(`[]`);
81
96
  });
82
97
  test('Check executing without parameters', async () => {
83
98
  await InstallCommand.run([]).catch(err => {
@@ -96,8 +111,9 @@ describe('source:install command tests', () => {
96
111
  });
97
112
  });
98
113
  test('Check executing with invalid variable type', async () => {
99
- const path = `-f=${__dirname}/../__fixtures__/variables-file-invalid.json`;
100
- await InstallCommand.run(['test-03', path]).catch(err => {
114
+ const newPath = path.join(__dirname, '/../__fixtures__/variables-file-invalid.json');
115
+ const runPath = `-f=${newPath}`;
116
+ await InstallCommand.run(['test-03', runPath]).catch(err => {
101
117
  expect(err.message).toEqual(
102
118
  chalk.red(
103
119
  `The next variables has invalid type.\nVariable: ENDPOINT_URL\nRequested type: string`,
@@ -9,13 +9,17 @@ OF ANY KIND, either express or implied. See the License for the specific languag
9
9
  governing permissions and limitations under the License.
10
10
  */
11
11
 
12
- const { Command, CliUx } = require('@oclif/core');
13
- const { promptConfirm, initRequestId } = require('../../../helpers');
14
- const GetCommand = require('./get');
12
+ const { Command, CliUx, Flags } = require('@oclif/core');
13
+ const {
14
+ promptConfirm,
15
+ initRequestId,
16
+ promptMultiselect,
17
+ promptSelect,
18
+ } = require('../../../helpers');
15
19
  const SourceRegistryStorage = require('source-registry-storage-adapter');
16
20
  const config = require('@adobe/aio-lib-core-config');
17
21
  const logger = require('../../../classes/logger');
18
-
22
+ const InstallCommand = require('./install');
19
23
 
20
24
  class DiscoverCommand extends Command {
21
25
  async run() {
@@ -23,6 +27,7 @@ class DiscoverCommand extends Command {
23
27
  await initRequestId();
24
28
 
25
29
  logger.info(`RequestId: ${global.requestId}`);
30
+ const { flags } = await this.parse(DiscoverCommand);
26
31
  const srs = new SourceRegistryStorage(config.get('api-mesh.sourceRegistry.path'));
27
32
  let list;
28
33
  try {
@@ -33,9 +38,22 @@ class DiscoverCommand extends Command {
33
38
  }
34
39
 
35
40
  this.generateSourcesTable(list);
36
- const needInstall = await promptConfirm(`Are you want to install sources?`);
41
+ let needInstall = false;
42
+
43
+ if (flags.confirm) {
44
+ needInstall = true;
45
+ } else {
46
+ needInstall = await promptConfirm(`Do you want to install sources?`);
47
+ }
48
+
37
49
  if (needInstall) {
38
- GetCommand.run(['-m']);
50
+ const toInstall = await this.handleMultiple(list);
51
+ const params = [];
52
+ toInstall.forEach(source => {
53
+ params.push('-s');
54
+ params.push(source);
55
+ });
56
+ InstallCommand.run(params);
39
57
  }
40
58
  } catch (error) {
41
59
  logger.error(error);
@@ -46,6 +64,38 @@ class DiscoverCommand extends Command {
46
64
  }
47
65
  }
48
66
 
67
+ async handleMultiple(data) {
68
+ const result = [];
69
+ let selectedList =
70
+ (await promptMultiselect(
71
+ 'Select sources to install',
72
+ Object.values(data).map(elem => ({ name: elem.name, value: elem })),
73
+ )) || [];
74
+
75
+ if (!selectedList.length) {
76
+ while (!selectedList.length) {
77
+ selectedList =
78
+ (await promptMultiselect(
79
+ 'Please choose at least one source',
80
+ Object.values(data).map(elem => ({ name: elem.name, value: elem })),
81
+ )) || [];
82
+ }
83
+ }
84
+
85
+ for (const selected of selectedList) {
86
+ if (selected.versions.length > 1) {
87
+ const version = await promptSelect(
88
+ `Please choose the version of "${selected.name}" source`,
89
+ selected.versions.map(v => ({ name: `v${v}`, value: `${selected.name}@${v}` })),
90
+ );
91
+ result.push(version);
92
+ } else {
93
+ result.push(`${selected.name}@${selected.latest}`);
94
+ }
95
+ }
96
+ return result;
97
+ }
98
+
49
99
  async generateSourcesTable(data) {
50
100
  const columns = {
51
101
  name: {
@@ -65,6 +115,15 @@ class DiscoverCommand extends Command {
65
115
  }
66
116
  }
67
117
 
118
+ DiscoverCommand.flags = {
119
+ confirm: Flags.boolean({
120
+ char: 'c',
121
+ description:
122
+ 'Auto confirm install action prompt. CLI will not check ask user to install source.',
123
+ default: false,
124
+ }),
125
+ };
126
+
68
127
  DiscoverCommand.description = 'Return the list of avaliable sources';
69
128
 
70
129
  module.exports = DiscoverCommand;