@adobe/aio-cli-plugin-api-mesh 2.3.0 → 2.3.2
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/oclif.manifest.json +1 -1
- package/package.json +1 -1
- package/src/commands/__fixtures__/sample_mesh_with_composer_files.json +42 -0
- package/src/commands/api-mesh/__tests__/create.test.js +215 -55
- package/src/commands/api-mesh/__tests__/describe.test.js +64 -2
- package/src/commands/api-mesh/create.js +8 -1
- package/src/commands/api-mesh/describe.js +5 -5
- package/src/utils.js +41 -16
package/oclif.manifest.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"2.3.
|
|
1
|
+
{"version":"2.3.2","commands":{"PLUGINNAME":{"id":"PLUGINNAME","description":"Your description here","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"examples":["$ aio PLUGINNAME:some_command"],"flags":{"someflag":{"name":"someflag","type":"option","char":"f","description":"this is some flag"}},"args":[]},"api-mesh:create":{"id":"api-mesh:create","description":"Create a mesh with the given config.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false},"json":{"name":"json","type":"boolean","description":"Output JSON","allowNo":false},"env":{"name":"env","type":"option","char":"e","description":"Path to env file","default":".env"}},"args":[{"name":"file"}]},"api-mesh:delete":{"id":"api-mesh:delete","description":"Delete the config of a given mesh","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false}},"args":[]},"api-mesh:describe":{"id":"api-mesh:describe","description":"Get details of a mesh","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false}},"args":[]},"api-mesh:get":{"id":"api-mesh:get","description":"Get the config of a given mesh","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"json":{"name":"json","type":"boolean","description":"Output JSON","allowNo":false}},"args":[{"name":"file"}]},"api-mesh:init":{"id":"api-mesh:init","description":"This command will create a workspace where you can organise your API mesh configuration and other files","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"examples":[{"description":"API mesh workspace init","command":"aio api-mesh init commerce-mesh"},{"description":"API mesh workspace init with flags","command":"aio api-mesh init commerce-mesh --path ./mesh_projects/test_mesh --git y --packageManager yarn"}],"flags":{"path":{"name":"path","type":"option","char":"p","default":"."},"packageManager":{"name":"packageManager","type":"option","char":"m","options":["npm","yarn"]},"git":{"name":"git","type":"option","char":"g","options":["y","n"]}},"args":[{"name":"projectName","description":"Project name","required":true}]},"api-mesh:status":{"id":"api-mesh:status","description":"Get a mesh status with a given meshid.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false}},"args":[]},"api-mesh:update":{"id":"api-mesh:update","description":"Update a mesh with the given config.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false},"env":{"name":"env","type":"option","char":"e","description":"Path to env file","default":".env"}},"args":[{"name":"file"}]},"api-mesh:source:discover":{"id":"api-mesh:source:discover","description":"Return the list of avaliable sources","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"confirm":{"name":"confirm","type":"boolean","char":"c","description":"Auto confirm install action prompt. CLI will not check ask user to install source.","allowNo":false}},"args":[]},"api-mesh:source:get":{"id":"api-mesh:source:get","description":"Command returns the content of a specific source.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"examples":["$ aio api-mesh:source:get -s=<version>@<source_name>","$ aio api-mesh:source:get -s<source_name>","$ aio api-mesh:source:get -m"],"flags":{"confirm":{"name":"confirm","type":"boolean","char":"c","description":"Auto confirm print action prompt. CLI will not check ask user to print source.","allowNo":false},"source":{"name":"source","type":"option","char":"s","description":"Source name"},"multiple":{"name":"multiple","type":"boolean","char":"m","description":"Select multiple sources","allowNo":false}},"args":[]},"api-mesh:source:install":{"id":"api-mesh:source:install","description":"Command to install the source to your API mesh.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"examples":["$ aio api-mesh:source:install <version>@<source_name>","$ aio api-mesh:source:install <source_name> -v <variable_name>=<variable_value>","$ aio api-mesh:source:install <source_name> -f <path_to_variables_file>"],"flags":{"source":{"name":"source","type":"option","char":"s","description":"Source name"},"confirm":{"name":"confirm","type":"boolean","char":"c","description":"Auto confirm override action prompt. CLI will not check ask user to override source.","allowNo":false},"variable":{"name":"variable","type":"option","char":"v","description":"Variables required for the source"},"variable-file":{"name":"variable-file","type":"option","char":"f","description":"Variables file path"},"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false}},"args":[{"name":"source"}]}}}
|
package/package.json
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meshConfig": {
|
|
3
|
+
"sources": [
|
|
4
|
+
{
|
|
5
|
+
"name": "<json_source_name>",
|
|
6
|
+
"handler": {
|
|
7
|
+
"JsonSchema": {
|
|
8
|
+
"baseUrl": "<json_source__baseurl>",
|
|
9
|
+
"operations": [
|
|
10
|
+
{
|
|
11
|
+
"type": "Query",
|
|
12
|
+
"field": "<query>",
|
|
13
|
+
"path": "<query_path>",
|
|
14
|
+
"method": "POST",
|
|
15
|
+
"requestSchema": "./requestParams.json"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"plugins": [
|
|
23
|
+
{
|
|
24
|
+
"hooks": {
|
|
25
|
+
"beforeAll": {
|
|
26
|
+
"composer": "./hooks.js#functionName"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"files": [
|
|
32
|
+
{
|
|
33
|
+
"path": "./requestParams.json",
|
|
34
|
+
"content": "{\"type\":\"dummyContent\"}"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"path": "./hooks.js",
|
|
38
|
+
"content": "module.exports.functionName = () => { console.log('beforeAll hook'); }"
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -14,6 +14,7 @@ const mockConsoleCLIInstance = {};
|
|
|
14
14
|
|
|
15
15
|
const CreateCommand = require('../create');
|
|
16
16
|
const sampleCreateMeshConfig = require('../../__fixtures__/sample_mesh.json');
|
|
17
|
+
const meshConfigWithComposerFiles = require('../../__fixtures__/sample_mesh_with_composer_files.json');
|
|
17
18
|
const {
|
|
18
19
|
initSdk,
|
|
19
20
|
initRequestId,
|
|
@@ -22,6 +23,7 @@ const {
|
|
|
22
23
|
importFiles,
|
|
23
24
|
} = require('../../../helpers');
|
|
24
25
|
const {
|
|
26
|
+
getMesh,
|
|
25
27
|
createMesh,
|
|
26
28
|
createAPIMeshCredentials,
|
|
27
29
|
subscribeCredentialToMeshService,
|
|
@@ -82,6 +84,12 @@ describe('create command tests', () => {
|
|
|
82
84
|
});
|
|
83
85
|
subscribeCredentialToMeshService.mockResolvedValue(['dummy_service']);
|
|
84
86
|
|
|
87
|
+
let fetchedMeshConfig = sampleCreateMeshConfig;
|
|
88
|
+
fetchedMeshConfig.meshId = 'dummy_id';
|
|
89
|
+
fetchedMeshConfig.meshURL = '';
|
|
90
|
+
|
|
91
|
+
getMesh.mockResolvedValue(fetchedMeshConfig);
|
|
92
|
+
|
|
85
93
|
parseSpy = jest.spyOn(CreateCommand.prototype, 'parse');
|
|
86
94
|
parseSpy.mockResolvedValue({
|
|
87
95
|
args: { file: 'src/commands/__fixtures__/sample_mesh.json' },
|
|
@@ -158,6 +166,78 @@ describe('create command tests', () => {
|
|
|
158
166
|
`);
|
|
159
167
|
expect(CreateCommand.aliases).toMatchInlineSnapshot(`[]`);
|
|
160
168
|
});
|
|
169
|
+
|
|
170
|
+
test('should pass if a valid mesh config file with composer files are provided', async () => {
|
|
171
|
+
createMesh.mockResolvedValueOnce({
|
|
172
|
+
meshId: 'dummy_mesh_id',
|
|
173
|
+
meshConfig: meshConfigWithComposerFiles.meshConfig,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
parseSpy.mockResolvedValueOnce({
|
|
177
|
+
args: { file: 'src/commands/__fixtures__/sample_mesh_with_composer_files.json' },
|
|
178
|
+
flags: {
|
|
179
|
+
autoConfirmAction: Promise.resolve(true),
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const output = await CreateCommand.run();
|
|
184
|
+
|
|
185
|
+
expect(output).toMatchInlineSnapshot(`
|
|
186
|
+
{
|
|
187
|
+
"adobeIdIntegrationsForWorkspace": {
|
|
188
|
+
"apiKey": "dummy_api_key",
|
|
189
|
+
"id": "dummy_id",
|
|
190
|
+
},
|
|
191
|
+
"mesh": {
|
|
192
|
+
"meshConfig": {
|
|
193
|
+
"files": [
|
|
194
|
+
{
|
|
195
|
+
"content": "{"type":"dummyContent"}",
|
|
196
|
+
"path": "./requestParams.json",
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"content": "module.exports.functionName = () => { console.log('beforeAll hook'); }",
|
|
200
|
+
"path": "./hooks.js",
|
|
201
|
+
},
|
|
202
|
+
],
|
|
203
|
+
"plugins": [
|
|
204
|
+
{
|
|
205
|
+
"hooks": {
|
|
206
|
+
"beforeAll": {
|
|
207
|
+
"composer": "./hooks.js#functionName",
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
],
|
|
212
|
+
"sources": [
|
|
213
|
+
{
|
|
214
|
+
"handler": {
|
|
215
|
+
"JsonSchema": {
|
|
216
|
+
"baseUrl": "<json_source__baseurl>",
|
|
217
|
+
"operations": [
|
|
218
|
+
{
|
|
219
|
+
"field": "<query>",
|
|
220
|
+
"method": "POST",
|
|
221
|
+
"path": "<query_path>",
|
|
222
|
+
"requestSchema": "./requestParams.json",
|
|
223
|
+
"type": "Query",
|
|
224
|
+
},
|
|
225
|
+
],
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
"name": "<json_source_name>",
|
|
229
|
+
},
|
|
230
|
+
],
|
|
231
|
+
},
|
|
232
|
+
"meshId": "dummy_mesh_id",
|
|
233
|
+
},
|
|
234
|
+
"sdkList": [
|
|
235
|
+
"dummy_service",
|
|
236
|
+
],
|
|
237
|
+
}
|
|
238
|
+
`);
|
|
239
|
+
});
|
|
240
|
+
|
|
161
241
|
test('should fail if create mesh api has failed', async () => {
|
|
162
242
|
createMesh.mockRejectedValueOnce(new Error('create mesh api failed'));
|
|
163
243
|
|
|
@@ -182,6 +262,7 @@ describe('create command tests', () => {
|
|
|
182
262
|
]
|
|
183
263
|
`);
|
|
184
264
|
});
|
|
265
|
+
|
|
185
266
|
test('should create if a valid mesh config file is provided', async () => {
|
|
186
267
|
const runResult = await CreateCommand.run();
|
|
187
268
|
|
|
@@ -284,6 +365,113 @@ describe('create command tests', () => {
|
|
|
284
365
|
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`[]`);
|
|
285
366
|
});
|
|
286
367
|
|
|
368
|
+
test('should create and return Ti mesh url if a valid mesh config file for TI client is provided', async () => {
|
|
369
|
+
let fetchedMeshConfig = sampleCreateMeshConfig;
|
|
370
|
+
fetchedMeshConfig.meshId = 'dummy_id';
|
|
371
|
+
fetchedMeshConfig.meshURL = 'https://tigraph.adobe.io';
|
|
372
|
+
getMesh.mockResolvedValueOnce(fetchedMeshConfig);
|
|
373
|
+
|
|
374
|
+
const runResult = await CreateCommand.run();
|
|
375
|
+
|
|
376
|
+
expect(initRequestId).toHaveBeenCalled();
|
|
377
|
+
expect(createMesh.mock.calls[0]).toMatchInlineSnapshot(`
|
|
378
|
+
[
|
|
379
|
+
"1234",
|
|
380
|
+
"5678",
|
|
381
|
+
"123456789",
|
|
382
|
+
{
|
|
383
|
+
"meshConfig": {
|
|
384
|
+
"sources": [
|
|
385
|
+
{
|
|
386
|
+
"handler": {
|
|
387
|
+
"graphql": {
|
|
388
|
+
"endpoint": "<gql_endpoint>",
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
"name": "<api_name>",
|
|
392
|
+
},
|
|
393
|
+
],
|
|
394
|
+
},
|
|
395
|
+
},
|
|
396
|
+
]
|
|
397
|
+
`);
|
|
398
|
+
expect(createAPIMeshCredentials.mock.calls[0]).toMatchInlineSnapshot(`
|
|
399
|
+
[
|
|
400
|
+
"1234",
|
|
401
|
+
"5678",
|
|
402
|
+
"123456789",
|
|
403
|
+
]
|
|
404
|
+
`);
|
|
405
|
+
expect(subscribeCredentialToMeshService.mock.calls[0]).toMatchInlineSnapshot(`
|
|
406
|
+
[
|
|
407
|
+
"1234",
|
|
408
|
+
"5678",
|
|
409
|
+
"123456789",
|
|
410
|
+
"dummy_id",
|
|
411
|
+
]
|
|
412
|
+
`);
|
|
413
|
+
expect(runResult).toMatchInlineSnapshot(`
|
|
414
|
+
{
|
|
415
|
+
"adobeIdIntegrationsForWorkspace": {
|
|
416
|
+
"apiKey": "dummy_api_key",
|
|
417
|
+
"id": "dummy_id",
|
|
418
|
+
},
|
|
419
|
+
"mesh": {
|
|
420
|
+
"meshConfig": {
|
|
421
|
+
"sources": [
|
|
422
|
+
{
|
|
423
|
+
"handler": {
|
|
424
|
+
"graphql": {
|
|
425
|
+
"endpoint": "<gql_endpoint>",
|
|
426
|
+
},
|
|
427
|
+
},
|
|
428
|
+
"name": "<api_name>",
|
|
429
|
+
},
|
|
430
|
+
],
|
|
431
|
+
},
|
|
432
|
+
"meshId": "dummy_mesh_id",
|
|
433
|
+
},
|
|
434
|
+
"sdkList": [
|
|
435
|
+
"dummy_service",
|
|
436
|
+
],
|
|
437
|
+
}
|
|
438
|
+
`);
|
|
439
|
+
expect(logSpy.mock.calls).toMatchInlineSnapshot(`
|
|
440
|
+
[
|
|
441
|
+
[
|
|
442
|
+
"******************************************************************************************************",
|
|
443
|
+
],
|
|
444
|
+
[
|
|
445
|
+
"Your mesh is being provisioned. Wait a few minutes before checking the status of your mesh %s",
|
|
446
|
+
"dummy_mesh_id",
|
|
447
|
+
],
|
|
448
|
+
[
|
|
449
|
+
"To check the status of your mesh, run:",
|
|
450
|
+
],
|
|
451
|
+
[
|
|
452
|
+
"aio api-mesh:status",
|
|
453
|
+
],
|
|
454
|
+
[
|
|
455
|
+
"******************************************************************************************************",
|
|
456
|
+
],
|
|
457
|
+
[
|
|
458
|
+
"Successfully created API Key %s",
|
|
459
|
+
"dummy_api_key",
|
|
460
|
+
],
|
|
461
|
+
[
|
|
462
|
+
"Successfully subscribed API Key %s to API Mesh service",
|
|
463
|
+
"dummy_api_key",
|
|
464
|
+
],
|
|
465
|
+
[
|
|
466
|
+
"Mesh Endpoint: %s
|
|
467
|
+
",
|
|
468
|
+
"https://tigraph.adobe.io/dummy_mesh_id/graphql?api_key=dummy_api_key",
|
|
469
|
+
],
|
|
470
|
+
]
|
|
471
|
+
`);
|
|
472
|
+
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`[]`);
|
|
473
|
+
});
|
|
474
|
+
|
|
287
475
|
test('should fail if mesh config file arg is missing', async () => {
|
|
288
476
|
parseSpy.mockResolvedValueOnce({
|
|
289
477
|
args: {},
|
|
@@ -639,7 +827,7 @@ describe('create command tests', () => {
|
|
|
639
827
|
});
|
|
640
828
|
|
|
641
829
|
test('should successfully create a mesh if provided env file is valid, mesh interpolation is successful and interpolated mesh is a valid JSON', async () => {
|
|
642
|
-
parseSpy.
|
|
830
|
+
parseSpy.mockResolvedValueOnce({
|
|
643
831
|
args: { file: 'src/commands/__fixtures__/sample_mesh_with_placeholder' },
|
|
644
832
|
flags: {
|
|
645
833
|
ignoreCache: mockIgnoreCacheFlag,
|
|
@@ -690,7 +878,7 @@ describe('create command tests', () => {
|
|
|
690
878
|
});
|
|
691
879
|
|
|
692
880
|
test('should return error if inputMesh is not a valid JSON', async () => {
|
|
693
|
-
parseSpy.
|
|
881
|
+
parseSpy.mockResolvedValueOnce({
|
|
694
882
|
args: { file: 'src/commands/__fixtures__/sample_invalid_mesh.txt' },
|
|
695
883
|
flags: {
|
|
696
884
|
ignoreCache: mockIgnoreCacheFlag,
|
|
@@ -741,12 +929,12 @@ describe('create command tests', () => {
|
|
|
741
929
|
],
|
|
742
930
|
};
|
|
743
931
|
|
|
744
|
-
createMesh.
|
|
932
|
+
createMesh.mockResolvedValueOnce({
|
|
745
933
|
meshId: 'dummy_mesh_id',
|
|
746
934
|
meshConfig: meshConfig,
|
|
747
935
|
});
|
|
748
936
|
|
|
749
|
-
parseSpy.
|
|
937
|
+
parseSpy.mockResolvedValueOnce({
|
|
750
938
|
args: { file: 'src/commands/__fixtures__/sample_mesh_files.json' },
|
|
751
939
|
flags: {
|
|
752
940
|
autoConfirmAction: Promise.resolve(false),
|
|
@@ -856,7 +1044,7 @@ describe('create command tests', () => {
|
|
|
856
1044
|
});
|
|
857
1045
|
|
|
858
1046
|
test('should fail if the file name is more than 25 characters', async () => {
|
|
859
|
-
parseSpy.
|
|
1047
|
+
parseSpy.mockResolvedValueOnce({
|
|
860
1048
|
args: { file: 'src/commands/__fixtures__/sample_mesh_invalid_file_name.json' },
|
|
861
1049
|
flags: {
|
|
862
1050
|
autoConfirmAction: Promise.resolve(false),
|
|
@@ -884,36 +1072,8 @@ describe('create command tests', () => {
|
|
|
884
1072
|
`);
|
|
885
1073
|
});
|
|
886
1074
|
|
|
887
|
-
test('should fail if the file paths in files array and filenames in sources, transforms, additionalResolvers do not match in mesh config', async () => {
|
|
888
|
-
parseSpy.mockResolvedValue({
|
|
889
|
-
args: { file: 'src/commands/__fixtures__/sample_mesh_mismatching_path.json' },
|
|
890
|
-
flags: {
|
|
891
|
-
autoConfirmAction: Promise.resolve(false),
|
|
892
|
-
},
|
|
893
|
-
});
|
|
894
|
-
|
|
895
|
-
const output = CreateCommand.run();
|
|
896
|
-
|
|
897
|
-
await expect(output).rejects.toEqual(new Error('Input mesh config is not valid.'));
|
|
898
|
-
|
|
899
|
-
expect(logSpy.mock.calls).toMatchInlineSnapshot(`
|
|
900
|
-
[
|
|
901
|
-
[
|
|
902
|
-
"Please make sure the file names are matching in meshConfig.",
|
|
903
|
-
],
|
|
904
|
-
]
|
|
905
|
-
`);
|
|
906
|
-
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
|
|
907
|
-
[
|
|
908
|
-
[
|
|
909
|
-
"Input mesh config is not valid.",
|
|
910
|
-
],
|
|
911
|
-
]
|
|
912
|
-
`);
|
|
913
|
-
});
|
|
914
|
-
|
|
915
1075
|
test('should fail if the file is of type other than js, json extension', async () => {
|
|
916
|
-
parseSpy.
|
|
1076
|
+
parseSpy.mockResolvedValueOnce({
|
|
917
1077
|
args: { file: 'src/commands/__fixtures__/sample_mesh_invalid_type.json' },
|
|
918
1078
|
flags: {
|
|
919
1079
|
autoConfirmAction: Promise.resolve(false),
|
|
@@ -941,7 +1101,7 @@ describe('create command tests', () => {
|
|
|
941
1101
|
});
|
|
942
1102
|
|
|
943
1103
|
test('should fail if the files do not exist in the mesh directory or subdirectory', async () => {
|
|
944
|
-
parseSpy.
|
|
1104
|
+
parseSpy.mockResolvedValueOnce({
|
|
945
1105
|
args: { file: 'src/commands/__fixtures__/sample_mesh_invalid_paths.json' },
|
|
946
1106
|
flags: {
|
|
947
1107
|
autoConfirmAction: Promise.resolve(false),
|
|
@@ -979,7 +1139,7 @@ describe('create command tests', () => {
|
|
|
979
1139
|
});
|
|
980
1140
|
|
|
981
1141
|
test('should fail if import files function fails', async () => {
|
|
982
|
-
parseSpy.
|
|
1142
|
+
parseSpy.mockResolvedValueOnce({
|
|
983
1143
|
args: { file: 'src/commands/__fixtures__/sample_mesh_files.json' },
|
|
984
1144
|
flags: {
|
|
985
1145
|
autoConfirmAction: Promise.resolve(false),
|
|
@@ -1044,19 +1204,19 @@ describe('create command tests', () => {
|
|
|
1044
1204
|
],
|
|
1045
1205
|
};
|
|
1046
1206
|
|
|
1047
|
-
promptConfirm.
|
|
1207
|
+
promptConfirm.mockResolvedValueOnce(false).mockResolvedValueOnce(true);
|
|
1048
1208
|
|
|
1049
|
-
importFiles.
|
|
1209
|
+
importFiles.mockResolvedValueOnce(meshConfig);
|
|
1050
1210
|
|
|
1051
|
-
createMesh.
|
|
1211
|
+
createMesh.mockResolvedValueOnce({
|
|
1052
1212
|
meshId: 'dummy_mesh_id',
|
|
1053
1213
|
meshConfig: meshConfig,
|
|
1054
1214
|
});
|
|
1055
1215
|
|
|
1056
|
-
parseSpy.
|
|
1216
|
+
parseSpy.mockResolvedValueOnce({
|
|
1057
1217
|
args: { file: 'src/commands/__fixtures__/sample_mesh_with_files_array.json' },
|
|
1058
1218
|
flags: {
|
|
1059
|
-
autoConfirmAction: Promise.resolve(
|
|
1219
|
+
autoConfirmAction: Promise.resolve(true),
|
|
1060
1220
|
},
|
|
1061
1221
|
});
|
|
1062
1222
|
|
|
@@ -1184,12 +1344,12 @@ describe('create command tests', () => {
|
|
|
1184
1344
|
],
|
|
1185
1345
|
};
|
|
1186
1346
|
|
|
1187
|
-
promptConfirm.
|
|
1347
|
+
promptConfirm.mockResolvedValueOnce(true).mockResolvedValueOnce(true);
|
|
1188
1348
|
|
|
1189
|
-
parseSpy.
|
|
1349
|
+
parseSpy.mockResolvedValueOnce({
|
|
1190
1350
|
args: { file: 'src/commands/__fixtures__/sample_mesh_with_files_array.json' },
|
|
1191
1351
|
flags: {
|
|
1192
|
-
autoConfirmAction: Promise.resolve(
|
|
1352
|
+
autoConfirmAction: Promise.resolve(true),
|
|
1193
1353
|
},
|
|
1194
1354
|
});
|
|
1195
1355
|
|
|
@@ -1197,7 +1357,7 @@ describe('create command tests', () => {
|
|
|
1197
1357
|
meshConfig,
|
|
1198
1358
|
});
|
|
1199
1359
|
|
|
1200
|
-
createMesh.
|
|
1360
|
+
createMesh.mockResolvedValueOnce({
|
|
1201
1361
|
meshId: 'dummy_mesh_id',
|
|
1202
1362
|
meshConfig: meshConfig,
|
|
1203
1363
|
});
|
|
@@ -1329,20 +1489,20 @@ describe('create command tests', () => {
|
|
|
1329
1489
|
],
|
|
1330
1490
|
};
|
|
1331
1491
|
|
|
1332
|
-
parseSpy.
|
|
1492
|
+
parseSpy.mockResolvedValueOnce({
|
|
1333
1493
|
args: { file: 'src/commands/__fixtures__/sample_fully_qualified_mesh.json' },
|
|
1334
1494
|
flags: {
|
|
1335
|
-
autoConfirmAction: Promise.resolve(
|
|
1495
|
+
autoConfirmAction: Promise.resolve(true),
|
|
1336
1496
|
},
|
|
1337
1497
|
});
|
|
1338
1498
|
|
|
1339
|
-
promptConfirm.
|
|
1499
|
+
promptConfirm.mockResolvedValueOnce(true);
|
|
1340
1500
|
|
|
1341
1501
|
importFiles.mockResolvedValueOnce({
|
|
1342
1502
|
meshConfig,
|
|
1343
1503
|
});
|
|
1344
1504
|
|
|
1345
|
-
createMesh.
|
|
1505
|
+
createMesh.mockResolvedValueOnce({
|
|
1346
1506
|
meshId: 'dummy_mesh_id',
|
|
1347
1507
|
meshConfig: meshConfig,
|
|
1348
1508
|
});
|
|
@@ -1473,15 +1633,15 @@ describe('create command tests', () => {
|
|
|
1473
1633
|
],
|
|
1474
1634
|
};
|
|
1475
1635
|
|
|
1476
|
-
createMesh.
|
|
1636
|
+
createMesh.mockResolvedValueOnce({
|
|
1477
1637
|
meshId: 'dummy_mesh_id',
|
|
1478
1638
|
meshConfig: meshConfig,
|
|
1479
1639
|
});
|
|
1480
1640
|
|
|
1481
|
-
parseSpy.
|
|
1641
|
+
parseSpy.mockResolvedValueOnce({
|
|
1482
1642
|
args: { file: 'src/commands/__fixtures__/sample_mesh_subdirectory.json' },
|
|
1483
1643
|
flags: {
|
|
1484
|
-
autoConfirmAction: Promise.resolve(
|
|
1644
|
+
autoConfirmAction: Promise.resolve(true),
|
|
1485
1645
|
},
|
|
1486
1646
|
});
|
|
1487
1647
|
|
|
@@ -1588,7 +1748,7 @@ describe('create command tests', () => {
|
|
|
1588
1748
|
});
|
|
1589
1749
|
|
|
1590
1750
|
test('should fail if the file is outside the workspace directory', async () => {
|
|
1591
|
-
parseSpy.
|
|
1751
|
+
parseSpy.mockResolvedValueOnce({
|
|
1592
1752
|
args: { file: 'src/commands/__fixtures__/sample_mesh_outside_workspace_dir.json' },
|
|
1593
1753
|
flags: {
|
|
1594
1754
|
autoConfirmAction: Promise.resolve(false),
|
|
@@ -1615,7 +1775,7 @@ describe('create command tests', () => {
|
|
|
1615
1775
|
});
|
|
1616
1776
|
|
|
1617
1777
|
test('should fail if the file has invalid JSON content', async () => {
|
|
1618
|
-
parseSpy.
|
|
1778
|
+
parseSpy.mockResolvedValueOnce({
|
|
1619
1779
|
args: { file: 'src/commands/__fixtures__/sample_mesh_invalid_file_content.json' },
|
|
1620
1780
|
flags: {
|
|
1621
1781
|
autoConfirmAction: Promise.resolve(false),
|
|
@@ -1652,7 +1812,7 @@ describe('create command tests', () => {
|
|
|
1652
1812
|
});
|
|
1653
1813
|
|
|
1654
1814
|
test('should fail if the file path starts from home directory i.e., path starts with ~/', async () => {
|
|
1655
|
-
parseSpy.
|
|
1815
|
+
parseSpy.mockResolvedValueOnce({
|
|
1656
1816
|
args: { file: 'src/commands/__fixtures__/sample_mesh_path_from_home.json' },
|
|
1657
1817
|
flags: {
|
|
1658
1818
|
autoConfirmAction: Promise.resolve(false),
|
|
@@ -28,7 +28,8 @@ jest.mock('../../../lib/devConsole');
|
|
|
28
28
|
|
|
29
29
|
const DescribeCommand = require('../describe');
|
|
30
30
|
const { initSdk, initRequestId } = require('../../../helpers');
|
|
31
|
-
const { describeMesh } = require('../../../lib/devConsole');
|
|
31
|
+
const { describeMesh, getMesh } = require('../../../lib/devConsole');
|
|
32
|
+
const sampleCreateMeshConfig = require('../../__fixtures__/sample_mesh.json');
|
|
32
33
|
|
|
33
34
|
const selectedOrg = { id: '1234', code: 'CODE1234@AdobeOrg', name: 'ORG01', type: 'entp' };
|
|
34
35
|
const selectedProject = { id: '5678', title: 'Project01' };
|
|
@@ -64,6 +65,12 @@ describe('describe command tests', () => {
|
|
|
64
65
|
ignoreCache: mockIgnoreCacheFlag,
|
|
65
66
|
},
|
|
66
67
|
});
|
|
68
|
+
|
|
69
|
+
let fetchedMeshConfig = sampleCreateMeshConfig;
|
|
70
|
+
fetchedMeshConfig.meshId = 'dummy_id';
|
|
71
|
+
fetchedMeshConfig.meshURL = '';
|
|
72
|
+
|
|
73
|
+
getMesh.mockResolvedValue(fetchedMeshConfig);
|
|
67
74
|
});
|
|
68
75
|
|
|
69
76
|
afterEach(() => {
|
|
@@ -172,7 +179,7 @@ describe('describe command tests', () => {
|
|
|
172
179
|
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`[]`);
|
|
173
180
|
});
|
|
174
181
|
|
|
175
|
-
test('should
|
|
182
|
+
test('should return Non TI url if request is Non Ti', async () => {
|
|
176
183
|
const runResult = await DescribeCommand.run();
|
|
177
184
|
|
|
178
185
|
expect(initRequestId).toHaveBeenCalled();
|
|
@@ -219,6 +226,61 @@ describe('describe command tests', () => {
|
|
|
219
226
|
"https://graph.adobe.io/api/dummy_meshId/graphql?api_key=dummy_apiKey",
|
|
220
227
|
],
|
|
221
228
|
]
|
|
229
|
+
`);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
test('should return Ti URL if api return TI url', async () => {
|
|
233
|
+
let fetchedMeshConfig = sampleCreateMeshConfig;
|
|
234
|
+
fetchedMeshConfig.meshId = 'dummy_id';
|
|
235
|
+
fetchedMeshConfig.meshURL = 'https://tigraph.adobe.io';
|
|
236
|
+
|
|
237
|
+
getMesh.mockResolvedValue(fetchedMeshConfig);
|
|
238
|
+
const runResult = await DescribeCommand.run();
|
|
239
|
+
|
|
240
|
+
expect(initRequestId).toHaveBeenCalled();
|
|
241
|
+
expect(describeMesh).toHaveBeenCalledWith(
|
|
242
|
+
selectedOrg.id,
|
|
243
|
+
selectedProject.id,
|
|
244
|
+
selectedWorkspace.id,
|
|
245
|
+
);
|
|
246
|
+
expect(runResult).toMatchInlineSnapshot(`
|
|
247
|
+
{
|
|
248
|
+
"apiKey": "dummy_apiKey",
|
|
249
|
+
"meshId": "dummy_meshId",
|
|
250
|
+
}
|
|
251
|
+
`);
|
|
252
|
+
expect(logSpy.mock.calls).toMatchInlineSnapshot(`
|
|
253
|
+
[
|
|
254
|
+
[
|
|
255
|
+
"Successfully retrieved mesh details
|
|
256
|
+
",
|
|
257
|
+
],
|
|
258
|
+
[
|
|
259
|
+
"Org ID: %s",
|
|
260
|
+
"1234",
|
|
261
|
+
],
|
|
262
|
+
[
|
|
263
|
+
"Project ID: %s",
|
|
264
|
+
"5678",
|
|
265
|
+
],
|
|
266
|
+
[
|
|
267
|
+
"Workspace ID: %s",
|
|
268
|
+
"123456789",
|
|
269
|
+
],
|
|
270
|
+
[
|
|
271
|
+
"Mesh ID: %s",
|
|
272
|
+
"dummy_meshId",
|
|
273
|
+
],
|
|
274
|
+
[
|
|
275
|
+
"API Key: %s",
|
|
276
|
+
"dummy_apiKey",
|
|
277
|
+
],
|
|
278
|
+
[
|
|
279
|
+
"Mesh Endpoint: %s
|
|
280
|
+
",
|
|
281
|
+
"https://tigraph.adobe.io/dummy_meshId/graphql?api_key=dummy_apiKey",
|
|
282
|
+
],
|
|
283
|
+
]
|
|
222
284
|
`);
|
|
223
285
|
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`[]`);
|
|
224
286
|
});
|
|
@@ -25,6 +25,7 @@ const {
|
|
|
25
25
|
validateAndInterpolateMesh,
|
|
26
26
|
} = require('../../utils');
|
|
27
27
|
const {
|
|
28
|
+
getMesh,
|
|
28
29
|
createMesh,
|
|
29
30
|
createAPIMeshCredentials,
|
|
30
31
|
subscribeCredentialToMeshService,
|
|
@@ -150,9 +151,15 @@ class CreateCommand extends Command {
|
|
|
150
151
|
adobeIdIntegrationsForWorkspace.apiKey,
|
|
151
152
|
);
|
|
152
153
|
|
|
154
|
+
const { meshURL } = await getMesh(imsOrgId, projectId, workspaceId, mesh.meshId);
|
|
155
|
+
const meshUrl =
|
|
156
|
+
meshURL === '' || meshURL === undefined
|
|
157
|
+
? MULTITENANT_GRAPHQL_SERVER_BASE_URL
|
|
158
|
+
: meshURL;
|
|
159
|
+
|
|
153
160
|
this.log(
|
|
154
161
|
'Mesh Endpoint: %s\n',
|
|
155
|
-
`${
|
|
162
|
+
`${meshUrl}/${mesh.meshId}/graphql?api_key=${adobeIdIntegrationsForWorkspace.apiKey}`,
|
|
156
163
|
);
|
|
157
164
|
} else {
|
|
158
165
|
this.log(
|
|
@@ -15,7 +15,7 @@ const logger = require('../../classes/logger');
|
|
|
15
15
|
const { initSdk, initRequestId } = require('../../helpers');
|
|
16
16
|
const CONSTANTS = require('../../constants');
|
|
17
17
|
const { ignoreCacheFlag } = require('../../utils');
|
|
18
|
-
const { describeMesh } = require('../../lib/devConsole');
|
|
18
|
+
const { describeMesh, getMesh } = require('../../lib/devConsole');
|
|
19
19
|
|
|
20
20
|
require('dotenv').config();
|
|
21
21
|
|
|
@@ -52,12 +52,12 @@ class DescribeCommand extends Command {
|
|
|
52
52
|
this.log('Workspace ID: %s', workspaceId);
|
|
53
53
|
this.log('Mesh ID: %s', meshId);
|
|
54
54
|
|
|
55
|
+
const { meshURL } = await getMesh(imsOrgId, projectId, workspaceId, meshId);
|
|
56
|
+
const meshUrl = meshURL === '' ? MULTITENANT_GRAPHQL_SERVER_BASE_URL : meshURL;
|
|
57
|
+
|
|
55
58
|
if (apiKey) {
|
|
56
59
|
this.log('API Key: %s', apiKey);
|
|
57
|
-
this.log(
|
|
58
|
-
'Mesh Endpoint: %s\n',
|
|
59
|
-
`${MULTITENANT_GRAPHQL_SERVER_BASE_URL}/${meshId}/graphql?api_key=${apiKey}`,
|
|
60
|
-
);
|
|
60
|
+
this.log('Mesh Endpoint: %s\n', `${meshUrl}/${meshId}/graphql?api_key=${apiKey}`);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
return meshDetails;
|
package/src/utils.js
CHANGED
|
@@ -88,7 +88,9 @@ function getFilesInMeshConfig(data, meshConfigName) {
|
|
|
88
88
|
data.meshConfig.sources.transforms?.forEach(transform => {
|
|
89
89
|
transform.replaceField?.replacements.forEach(replacement => {
|
|
90
90
|
if (replacement.composer && !fileURLRegex.test(replacement.composer)) {
|
|
91
|
-
|
|
91
|
+
const [filename] = replacement.composer.split('#');
|
|
92
|
+
|
|
93
|
+
filesList.push(filename);
|
|
92
94
|
}
|
|
93
95
|
});
|
|
94
96
|
});
|
|
@@ -97,16 +99,51 @@ function getFilesInMeshConfig(data, meshConfigName) {
|
|
|
97
99
|
data.meshConfig.transforms?.forEach(transform => {
|
|
98
100
|
transform.replaceField?.replacements.forEach(replacement => {
|
|
99
101
|
if (replacement.composer && !fileURLRegex.test(replacement.composer)) {
|
|
100
|
-
|
|
102
|
+
const [filename] = replacement.composer.split('#');
|
|
103
|
+
|
|
104
|
+
filesList.push(filename);
|
|
101
105
|
}
|
|
102
106
|
});
|
|
103
107
|
});
|
|
104
108
|
|
|
109
|
+
// Hooks Plugin - mesh level
|
|
110
|
+
data.meshConfig.plugins?.forEach(plugin => {
|
|
111
|
+
if (plugin.hooks) {
|
|
112
|
+
if (plugin.hooks.beforeAll) {
|
|
113
|
+
const composer = plugin.hooks.beforeAll.composer;
|
|
114
|
+
|
|
115
|
+
if (composer && !fileURLRegex.test(composer)) {
|
|
116
|
+
const [filename] = composer.split('#');
|
|
117
|
+
|
|
118
|
+
filesList.push(filename);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// OnFetch plugin - mesh level
|
|
125
|
+
data.meshConfig.plugins?.forEach(plugin => {
|
|
126
|
+
if (plugin.onFetch) {
|
|
127
|
+
plugin.onFetch.forEach(onFetchConfig => {
|
|
128
|
+
const handler = onFetchConfig.handler;
|
|
129
|
+
|
|
130
|
+
if (handler) {
|
|
131
|
+
filesList.push(handler);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// remove duplicate files
|
|
138
|
+
filesList = [...new Set(filesList)];
|
|
139
|
+
|
|
140
|
+
logger.info(`Files to be imported: ${filesList.join(', ')}`);
|
|
141
|
+
|
|
105
142
|
try {
|
|
106
143
|
if (filesList.length) {
|
|
107
144
|
checkFilesAreUnderMeshDirectory(filesList, meshConfigName);
|
|
108
145
|
validateFileType(filesList);
|
|
109
|
-
validateFileName(filesList
|
|
146
|
+
validateFileName(filesList);
|
|
110
147
|
}
|
|
111
148
|
} catch (err) {
|
|
112
149
|
logger.error(err.message);
|
|
@@ -226,9 +263,8 @@ function validateFileType(filesList) {
|
|
|
226
263
|
* Validate the filenames
|
|
227
264
|
*
|
|
228
265
|
* @param filesList Files in sources, tranforms or additionalResolvers in the meshConfig
|
|
229
|
-
* @param data MeshConfig
|
|
230
266
|
*/
|
|
231
|
-
function validateFileName(filesList
|
|
267
|
+
function validateFileName(filesList) {
|
|
232
268
|
const filesWithInvalidNames = [];
|
|
233
269
|
|
|
234
270
|
// Check if the file names are less than 25 characters
|
|
@@ -244,17 +280,6 @@ function validateFileName(filesList, data) {
|
|
|
244
280
|
`Mesh file names must be less than 25 characters. The following file(s) are invalid: ${filesWithInvalidNames}.`,
|
|
245
281
|
);
|
|
246
282
|
}
|
|
247
|
-
|
|
248
|
-
// check if the the filePaths in the files array match
|
|
249
|
-
// the fileNames in sources, transforms or additionalResolvers
|
|
250
|
-
|
|
251
|
-
if (data.meshConfig.files) {
|
|
252
|
-
for (let i = 0; i < data.meshConfig.files.length; i++) {
|
|
253
|
-
if (filesList.indexOf(data.meshConfig.files[i].path) == -1) {
|
|
254
|
-
throw new Error(`Please make sure the file names are matching in meshConfig.`);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
283
|
}
|
|
259
284
|
|
|
260
285
|
/**validates the environment file content
|