@adobe/aio-cli-plugin-api-mesh 3.2.2 → 3.3.0-alpha

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.
@@ -1 +1 @@
1
- {"version":"3.2.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:run":{"id":"api-mesh:run","description":"Run a local development server that builds and compiles a mesh locally","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"examples":[],"flags":{"port":{"name":"port","type":"option","char":"p","description":"Port number for the local dev server"},"debug":{"name":"debug","type":"boolean","description":"Enable debugging mode","allowNo":false},"env":{"name":"env","type":"option","char":"e","description":"Path to env file","default":".env"},"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},"select":{"name":"select","type":"boolean","description":"Retrieve existing artifacts from the mesh","allowNo":false}},"args":[{"name":"file","description":"Mesh File"}]},"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"}]}}}
1
+ {"version":"3.3.0-alpha","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:run":{"id":"api-mesh:run","description":"Run a local development server that builds and compiles a mesh locally","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"examples":[],"flags":{"port":{"name":"port","type":"option","char":"p","description":"Port number for the local dev server"},"debug":{"name":"debug","type":"boolean","description":"Enable debugging mode","allowNo":false},"env":{"name":"env","type":"option","char":"e","description":"Path to env file","default":".env"},"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},"select":{"name":"select","type":"boolean","description":"Retrieve existing artifacts from the mesh","allowNo":false}},"args":[{"name":"file","description":"Mesh File"}]},"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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/aio-cli-plugin-api-mesh",
3
- "version": "3.2.2",
3
+ "version": "3.3.0-alpha",
4
4
  "description": "Adobe I/O CLI plugin to develop and manage API mesh sources",
5
5
  "keywords": [
6
6
  "oclif-plugin"
@@ -37,7 +37,7 @@
37
37
  "version": "oclif-dev readme && git add README.md"
38
38
  },
39
39
  "dependencies": {
40
- "@adobe-apimesh/mesh-builder": "1.4.0",
40
+ "@adobe-apimesh/mesh-builder": "1.4.4",
41
41
  "@adobe/aio-cli-lib-console": "^4.0.0",
42
42
  "@adobe/aio-lib-core-config": "^3.0.0",
43
43
  "@adobe/aio-lib-core-logging": "^2.0.0",
@@ -1,4 +1,4 @@
1
1
  {
2
- "$schema": "http://json-schema.org/draft-04/schema"
2
+ "$schema": "http://json-schema.org/draft-04/schema",
3
3
  "id": "2"
4
4
  }
@@ -12,6 +12,22 @@ governing permissions and limitations under the License.
12
12
 
13
13
  const mockConsoleCLIInstance = {};
14
14
 
15
+ jest.mock('axios');
16
+ jest.mock('@adobe/aio-lib-ims');
17
+ jest.mock('@adobe/aio-lib-env');
18
+ jest.mock('@adobe/aio-cli-lib-console', () => ({
19
+ init: jest.fn().mockResolvedValue(mockConsoleCLIInstance),
20
+ cleanStdOut: jest.fn(),
21
+ }));
22
+ jest.mock('../../../helpers', () => ({
23
+ initSdk: jest.fn().mockResolvedValue({}),
24
+ initRequestId: jest.fn().mockResolvedValue({}),
25
+ promptConfirm: jest.fn().mockResolvedValue(true),
26
+ interpolateMesh: jest.fn().mockResolvedValue({}),
27
+ importFiles: jest.fn().mockResolvedValue(),
28
+ }));
29
+ jest.mock('../../../lib/devConsole');
30
+
15
31
  const CreateCommand = require('../create');
16
32
  const sampleCreateMeshConfig = require('../../__fixtures__/sample_mesh.json');
17
33
  const meshConfigWithComposerFiles = require('../../__fixtures__/sample_mesh_with_composer_files.json');
@@ -27,35 +43,15 @@ const {
27
43
  createMesh,
28
44
  createAPIMeshCredentials,
29
45
  subscribeCredentialToMeshService,
46
+ getTenantFeatures,
30
47
  } = require('../../../lib/devConsole');
31
48
 
32
49
  const selectedOrg = { id: '1234', code: 'CODE1234@AdobeOrg', name: 'ORG01', type: 'entp' };
33
-
34
50
  const selectedProject = { id: '5678', title: 'Project01' };
35
-
36
51
  const selectedWorkspace = { id: '123456789', title: 'Workspace01' };
37
52
 
38
- jest.mock('@adobe/aio-cli-lib-console', () => ({
39
- init: jest.fn().mockResolvedValue(mockConsoleCLIInstance),
40
- cleanStdOut: jest.fn(),
41
- }));
42
-
43
- jest.mock('axios');
44
- jest.mock('@adobe/aio-lib-ims');
45
- jest.mock('@adobe/aio-lib-env');
46
- jest.mock('@adobe/aio-cli-lib-console');
47
- jest.mock('../../../helpers', () => ({
48
- initSdk: jest.fn().mockResolvedValue({}),
49
- initRequestId: jest.fn().mockResolvedValue({}),
50
- promptConfirm: jest.fn().mockResolvedValue(true),
51
- interpolateMesh: jest.fn().mockResolvedValue({}),
52
- importFiles: jest.fn().mockResolvedValue(),
53
- }));
54
- jest.mock('../../../lib/devConsole');
55
-
56
53
  let logSpy = null;
57
54
  let errorLogSpy = null;
58
-
59
55
  let parseSpy = null;
60
56
 
61
57
  const mockIgnoreCacheFlag = Promise.resolve(true);
@@ -65,16 +61,14 @@ describe('create command tests', () => {
65
61
  beforeEach(() => {
66
62
  initSdk.mockResolvedValue({
67
63
  imsOrgId: selectedOrg.id,
64
+ imsOrgCode: selectedOrg.code,
68
65
  projectId: selectedProject.id,
69
66
  workspaceId: selectedWorkspace.id,
70
67
  workspaceName: selectedWorkspace.title,
68
+ orgName: selectedOrg.name,
69
+ projectName: selectedProject.title,
71
70
  });
72
71
 
73
- global.requestId = 'dummy_request_id';
74
-
75
- logSpy = jest.spyOn(CreateCommand.prototype, 'log');
76
- errorLogSpy = jest.spyOn(CreateCommand.prototype, 'error');
77
-
78
72
  createMesh.mockResolvedValue({
79
73
  mesh: {
80
74
  meshId: 'dummy_mesh_id',
@@ -88,14 +82,23 @@ describe('create command tests', () => {
88
82
  apiKey: 'dummy_api_key',
89
83
  id: 'dummy_id',
90
84
  });
85
+
91
86
  subscribeCredentialToMeshService.mockResolvedValue(['dummy_service']);
92
87
 
93
- let fetchedMeshConfig = sampleCreateMeshConfig;
94
- fetchedMeshConfig.meshId = 'dummy_id';
95
- fetchedMeshConfig.meshURL = '';
88
+ getMesh.mockResolvedValue({
89
+ meshId: 'dummy_id',
90
+ meshURL: '',
91
+ });
96
92
 
97
- getMesh.mockResolvedValue(fetchedMeshConfig);
93
+ getTenantFeatures.mockResolvedValue({
94
+ imsOrgId: selectedProject.code,
95
+ showCloudflareURL: false,
96
+ });
98
97
 
98
+ global.requestId = 'dummy_request_id';
99
+
100
+ logSpy = jest.spyOn(CreateCommand.prototype, 'log');
101
+ errorLogSpy = jest.spyOn(CreateCommand.prototype, 'error');
99
102
  parseSpy = jest.spyOn(CreateCommand.prototype, 'parse');
100
103
  parseSpy.mockResolvedValue({
101
104
  args: { file: 'src/commands/__fixtures__/sample_mesh.json' },
@@ -280,6 +283,8 @@ describe('create command tests', () => {
280
283
  "5678",
281
284
  "123456789",
282
285
  "Workspace01",
286
+ "ORG01",
287
+ "Project01",
283
288
  {
284
289
  "meshConfig": {
285
290
  "sources": [
@@ -370,6 +375,8 @@ describe('create command tests', () => {
370
375
  "5678",
371
376
  "123456789",
372
377
  "Workspace01",
378
+ "ORG01",
379
+ "Project01",
373
380
  {
374
381
  "meshConfig": {
375
382
  "sources": [
@@ -929,6 +936,8 @@ describe('create command tests', () => {
929
936
  "5678",
930
937
  "123456789",
931
938
  "Workspace01",
939
+ "ORG01",
940
+ "Project01",
932
941
  {
933
942
  "meshConfig": {
934
943
  "files": [
@@ -1133,7 +1142,8 @@ describe('create command tests', () => {
1133
1142
  `);
1134
1143
  });
1135
1144
 
1136
- test('should not override if prompt returns No, if there is files array', async () => {
1145
+ // Temporarily skipping since it is not actually testing the file import override prompt. The function which performs the prompt is mocked.
1146
+ test.skip('should not override if prompt returns No, if there is files array', async () => {
1137
1147
  let meshConfig = {
1138
1148
  sources: [
1139
1149
  {
@@ -1191,6 +1201,8 @@ describe('create command tests', () => {
1191
1201
  "5678",
1192
1202
  "123456789",
1193
1203
  "Workspace01",
1204
+ "ORG01",
1205
+ "Project01",
1194
1206
  {
1195
1207
  "files": [
1196
1208
  {
@@ -1260,7 +1272,8 @@ describe('create command tests', () => {
1260
1272
  `);
1261
1273
  });
1262
1274
 
1263
- test('should override if prompt returns Yes, if there is files array', async () => {
1275
+ // Temporarily skipping since it is not actually testing the file import override prompt. The function which performs the prompt is mocked.
1276
+ test.skip('should override if prompt returns Yes, if there is files array', async () => {
1264
1277
  let meshConfig = {
1265
1278
  sources: [
1266
1279
  {
@@ -1320,6 +1333,8 @@ describe('create command tests', () => {
1320
1333
  "5678",
1321
1334
  "123456789",
1322
1335
  "Workspace01",
1336
+ "ORG01",
1337
+ "Project01",
1323
1338
  {
1324
1339
  "meshConfig": {
1325
1340
  "files": [
@@ -1452,6 +1467,8 @@ describe('create command tests', () => {
1452
1467
  "5678",
1453
1468
  "123456789",
1454
1469
  "Workspace01",
1470
+ "ORG01",
1471
+ "Project01",
1455
1472
  {
1456
1473
  "meshConfig": {
1457
1474
  "files": [
@@ -1581,6 +1598,8 @@ describe('create command tests', () => {
1581
1598
  "5678",
1582
1599
  "123456789",
1583
1600
  "Workspace01",
1601
+ "ORG01",
1602
+ "Project01",
1584
1603
  {
1585
1604
  "meshConfig": {
1586
1605
  "files": [
@@ -1742,4 +1761,74 @@ describe('create command tests', () => {
1742
1761
  ]
1743
1762
  `);
1744
1763
  });
1764
+
1765
+ test('should show prod edge mesh url on workspace named "Production" if feature is enabled', async () => {
1766
+ // mock the edge mesh url feature to be enabled
1767
+ getTenantFeatures.mockResolvedValue({
1768
+ imsOrgId: selectedOrg.code,
1769
+ showCloudflareURL: true,
1770
+ });
1771
+
1772
+ // mock the workspace name to "Production"
1773
+ initSdk.mockResolvedValue({
1774
+ workspaceName: 'Production',
1775
+ });
1776
+
1777
+ await CreateCommand.run();
1778
+
1779
+ expect(logSpy).toHaveBeenCalledWith(
1780
+ expect.stringContaining('Legacy Mesh Endpoint:'),
1781
+ 'https://graph.adobe.io/api/dummy_mesh_id/graphql?api_key=dummy_api_key',
1782
+ );
1783
+
1784
+ expect(logSpy).toHaveBeenCalledWith(
1785
+ expect.stringContaining('Edge Mesh Endpoint:'),
1786
+ 'https://edge-graph.adobe.io/api/dummy_mesh_id/graphql',
1787
+ );
1788
+ });
1789
+
1790
+ test('should show sandbox edge mesh url on workspace NOT named "Production" if feature is enabled', async () => {
1791
+ // mock the edge mesh url feature to be enabled
1792
+ getTenantFeatures.mockResolvedValueOnce({
1793
+ imsOrgId: selectedOrg.code,
1794
+ showCloudflareURL: true,
1795
+ });
1796
+
1797
+ // mock the workspace name to a value not equal to "Production"
1798
+ initSdk.mockResolvedValueOnce({
1799
+ workspaceName: 'AnythingButProduction',
1800
+ });
1801
+
1802
+ await CreateCommand.run();
1803
+
1804
+ expect(logSpy).toHaveBeenCalledWith(
1805
+ expect.stringContaining('Legacy Mesh Endpoint:'),
1806
+ 'https://graph.adobe.io/api/dummy_mesh_id/graphql?api_key=dummy_api_key',
1807
+ );
1808
+
1809
+ expect(logSpy).toHaveBeenCalledWith(
1810
+ expect.stringContaining('Edge Mesh Endpoint:'),
1811
+ 'https://edge-sandbox-graph.adobe.io/api/dummy_mesh_id/graphql',
1812
+ );
1813
+ });
1814
+
1815
+ test('should not show edge mesh url if feature is disabled', async () => {
1816
+ // mock the edge mesh url feature to be disabled
1817
+ getTenantFeatures.mockResolvedValueOnce({
1818
+ imsOrgId: selectedOrg.code,
1819
+ showCloudflareURL: false,
1820
+ });
1821
+
1822
+ await CreateCommand.run();
1823
+
1824
+ expect(logSpy).not.toHaveBeenCalledWith(
1825
+ expect.stringContaining('Edge Mesh Endpoint:'),
1826
+ expect.any(String),
1827
+ );
1828
+
1829
+ expect(logSpy).toHaveBeenCalledWith(
1830
+ expect.stringContaining('Mesh Endpoint:'),
1831
+ 'https://graph.adobe.io/api/dummy_mesh_id/graphql?api_key=dummy_api_key',
1832
+ );
1833
+ });
1745
1834
  });
@@ -14,7 +14,6 @@ const mockConsoleCLIInstance = {};
14
14
 
15
15
  jest.mock('axios');
16
16
  jest.mock('@adobe/aio-lib-env');
17
- jest.mock('@adobe/aio-cli-lib-console');
18
17
  jest.mock('@adobe/aio-lib-ims');
19
18
  jest.mock('../../../helpers', () => ({
20
19
  initSdk: jest.fn().mockResolvedValue({}),
@@ -28,7 +27,7 @@ jest.mock('../../../lib/devConsole');
28
27
 
29
28
  const DescribeCommand = require('../describe');
30
29
  const { initSdk, initRequestId } = require('../../../helpers');
31
- const { describeMesh, getMesh } = require('../../../lib/devConsole');
30
+ const { describeMesh, getMesh, getTenantFeatures } = require('../../../lib/devConsole');
32
31
  const sampleCreateMeshConfig = require('../../__fixtures__/sample_mesh.json');
33
32
 
34
33
  const selectedOrg = { id: '1234', code: 'CODE1234@AdobeOrg', name: 'ORG01', type: 'entp' };
@@ -43,35 +42,39 @@ const mockIgnoreCacheFlag = jest.fn().mockResolvedValue(true);
43
42
 
44
43
  describe('describe command tests', () => {
45
44
  beforeEach(() => {
46
- describeMesh.mockResolvedValue({
47
- meshId: 'dummy_meshId',
48
- apiKey: 'dummy_apiKey',
49
- });
50
-
51
45
  initSdk.mockResolvedValue({
52
46
  imsOrgId: selectedOrg.id,
47
+ imsOrgCode: selectedOrg.code,
53
48
  projectId: selectedProject.id,
54
49
  workspaceId: selectedWorkspace.id,
55
50
  workspaceName: selectedWorkspace.title,
56
51
  });
57
52
 
53
+ describeMesh.mockResolvedValue({
54
+ meshId: 'dummy_meshId',
55
+ apiKey: 'dummy_apiKey',
56
+ });
57
+
58
+ getMesh.mockResolvedValue({
59
+ meshId: 'dummy_id',
60
+ meshURL: '',
61
+ });
62
+
63
+ getTenantFeatures.mockResolvedValue({
64
+ imsOrgId: selectedOrg.code,
65
+ showCloudflareURL: false,
66
+ });
67
+
58
68
  global.requestId = 'dummy_request_id';
59
69
 
60
70
  logSpy = jest.spyOn(DescribeCommand.prototype, 'log');
61
71
  errorLogSpy = jest.spyOn(DescribeCommand.prototype, 'error');
62
-
63
72
  parseSpy = jest.spyOn(DescribeCommand.prototype, 'parse');
64
73
  parseSpy.mockResolvedValue({
65
74
  flags: {
66
75
  ignoreCache: mockIgnoreCacheFlag,
67
76
  },
68
77
  });
69
-
70
- let fetchedMeshConfig = sampleCreateMeshConfig;
71
- fetchedMeshConfig.meshId = 'dummy_id';
72
- fetchedMeshConfig.meshURL = '';
73
-
74
- getMesh.mockResolvedValue(fetchedMeshConfig);
75
78
  });
76
79
 
77
80
  afterEach(() => {
@@ -284,4 +287,74 @@ describe('describe command tests', () => {
284
287
  `);
285
288
  expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`[]`);
286
289
  });
290
+
291
+ test('should show prod edge mesh url on workspace named "Production" if feature is enabled', async () => {
292
+ // mock the edge mesh url feature to be enabled
293
+ getTenantFeatures.mockResolvedValueOnce({
294
+ imsOrgId: selectedOrg.code,
295
+ showCloudflareURL: true,
296
+ });
297
+
298
+ // mock the workspace name to "Production"
299
+ initSdk.mockResolvedValueOnce({
300
+ workspaceName: 'Production',
301
+ });
302
+
303
+ await DescribeCommand.run();
304
+
305
+ expect(logSpy).toHaveBeenCalledWith(
306
+ expect.stringContaining('Legacy Mesh Endpoint:'),
307
+ 'https://graph.adobe.io/api/dummy_meshId/graphql?api_key=dummy_apiKey',
308
+ );
309
+
310
+ expect(logSpy).toHaveBeenCalledWith(
311
+ expect.stringContaining('Edge Mesh Endpoint:'),
312
+ 'https://edge-graph.adobe.io/api/dummy_meshId/graphql',
313
+ );
314
+ });
315
+
316
+ test('should show sandbox edge mesh url on workspace NOT named "Production" if feature is enabled', async () => {
317
+ // mock the edge mesh url feature to be enabled
318
+ getTenantFeatures.mockResolvedValueOnce({
319
+ imsOrgId: selectedOrg.code,
320
+ showCloudflareURL: true,
321
+ });
322
+
323
+ // mock the workspace name to a value not equal to "Production"
324
+ initSdk.mockResolvedValueOnce({
325
+ workspaceName: 'AnythingButProduction',
326
+ });
327
+
328
+ await DescribeCommand.run();
329
+
330
+ expect(logSpy).toHaveBeenCalledWith(
331
+ expect.stringContaining('Legacy Mesh Endpoint:'),
332
+ 'https://graph.adobe.io/api/dummy_meshId/graphql?api_key=dummy_apiKey',
333
+ );
334
+
335
+ expect(logSpy).toHaveBeenCalledWith(
336
+ expect.stringContaining('Edge Mesh Endpoint:'),
337
+ 'https://edge-sandbox-graph.adobe.io/api/dummy_meshId/graphql',
338
+ );
339
+ });
340
+
341
+ test('should not show edge mesh url if feature is disabled', async () => {
342
+ // mock the edge mesh url feature to be disabled
343
+ getTenantFeatures.mockResolvedValueOnce({
344
+ imsOrgId: selectedOrg.code,
345
+ showCloudflareURL: false,
346
+ });
347
+
348
+ await DescribeCommand.run();
349
+
350
+ expect(logSpy).not.toHaveBeenCalledWith(
351
+ expect.stringContaining('Edge Mesh Endpoint:'),
352
+ expect.any(String),
353
+ );
354
+
355
+ expect(logSpy).toHaveBeenCalledWith(
356
+ expect.stringContaining('Mesh Endpoint:'),
357
+ 'https://graph.adobe.io/api/dummy_meshId/graphql?api_key=dummy_apiKey',
358
+ );
359
+ });
287
360
  });
@@ -10,9 +10,9 @@ governing permissions and limitations under the License.
10
10
  */
11
11
 
12
12
  const { Command } = require('@oclif/core');
13
+ const chalk = require('chalk');
13
14
  const { initSdk, initRequestId, promptConfirm, importFiles } = require('../../helpers');
14
15
  const logger = require('../../classes/logger');
15
- const CONSTANTS = require('../../constants');
16
16
  const {
17
17
  ignoreCacheFlag,
18
18
  autoConfirmActionFlag,
@@ -23,9 +23,8 @@ const {
23
23
  readFileContents,
24
24
  validateAndInterpolateMesh,
25
25
  } = require('../../utils');
26
- const { getMesh, createMesh } = require('../../lib/devConsole');
27
-
28
- const { MULTITENANT_GRAPHQL_SERVER_BASE_URL } = CONSTANTS;
26
+ const { createMesh, getTenantFeatures } = require('../../lib/devConsole');
27
+ const { buildEdgeMeshUrl, buildMeshUrl } = require('../../urlBuilder');
29
28
 
30
29
  class CreateCommand extends Command {
31
30
  static args = [{ name: 'file' }];
@@ -54,7 +53,15 @@ class CreateCommand extends Command {
54
53
  const ignoreCache = await flags.ignoreCache;
55
54
  const autoConfirmAction = await flags.autoConfirmAction;
56
55
  const envFilePath = await flags.env;
57
- const { imsOrgId, projectId, workspaceId, workspaceName } = await initSdk({
56
+ const {
57
+ imsOrgId,
58
+ imsOrgCode,
59
+ projectId,
60
+ workspaceId,
61
+ workspaceName,
62
+ orgName,
63
+ projectName,
64
+ } = await initSdk({
58
65
  ignoreCache,
59
66
  });
60
67
 
@@ -109,6 +116,8 @@ class CreateCommand extends Command {
109
116
  projectId,
110
117
  workspaceId,
111
118
  workspaceName,
119
+ orgName,
120
+ projectName,
112
121
  data,
113
122
  );
114
123
 
@@ -132,25 +141,23 @@ class CreateCommand extends Command {
132
141
  if (sdkList) {
133
142
  this.log('Successfully subscribed API Key %s to API Mesh service', apiKey);
134
143
 
135
- const { meshURL } = await getMesh(
144
+ const meshUrl = await buildMeshUrl(
136
145
  imsOrgId,
137
146
  projectId,
138
147
  workspaceId,
139
148
  workspaceName,
140
149
  mesh.meshId,
150
+ apiKey,
141
151
  );
142
- const meshUrl =
143
- meshURL === '' || meshURL === undefined
144
- ? MULTITENANT_GRAPHQL_SERVER_BASE_URL
145
- : meshURL;
146
-
147
- if (apiKey && MULTITENANT_GRAPHQL_SERVER_BASE_URL.includes(meshUrl)) {
148
- this.log(
149
- 'Mesh Endpoint: %s\n',
150
- `${meshUrl}/${mesh.meshId}/graphql?api_key=${apiKey}`,
151
- );
152
+
153
+ const { showCloudflareURL: showEdgeMeshUrl } = await getTenantFeatures(imsOrgCode);
154
+
155
+ if (showEdgeMeshUrl) {
156
+ const edgeMeshUrl = buildEdgeMeshUrl(mesh.meshId, workspaceName);
157
+ this.log('Legacy Mesh Endpoint: %s', meshUrl);
158
+ this.log(chalk.bold('Edge Mesh Endpoint: %s\n'), edgeMeshUrl);
152
159
  } else {
153
- this.log('Mesh Endpoint: %s\n', `${meshUrl}/${mesh.meshId}/graphql`);
160
+ this.log('Mesh Endpoint: %s\n', meshUrl);
154
161
  }
155
162
  } else {
156
163
  this.log('Unable to subscribe API Key %s to API Mesh service', apiKey);
@@ -10,17 +10,16 @@ governing permissions and limitations under the License.
10
10
  */
11
11
 
12
12
  const { Command } = require('@oclif/command');
13
+ const chalk = require('chalk');
13
14
 
14
15
  const logger = require('../../classes/logger');
15
16
  const { initSdk, initRequestId } = require('../../helpers');
16
- const CONSTANTS = require('../../constants');
17
17
  const { ignoreCacheFlag } = require('../../utils');
18
- const { describeMesh, getMesh } = require('../../lib/devConsole');
18
+ const { describeMesh, getTenantFeatures } = require('../../lib/devConsole');
19
+ const { buildMeshUrl, buildEdgeMeshUrl } = require('../../urlBuilder');
19
20
 
20
21
  require('dotenv').config();
21
22
 
22
- const { MULTITENANT_GRAPHQL_SERVER_BASE_URL } = CONSTANTS;
23
-
24
23
  class DescribeCommand extends Command {
25
24
  static flags = {
26
25
  ignoreCache: ignoreCacheFlag,
@@ -32,10 +31,8 @@ class DescribeCommand extends Command {
32
31
  logger.info(`RequestId: ${global.requestId}`);
33
32
 
34
33
  const { flags } = await this.parse(DescribeCommand);
35
-
36
34
  const ignoreCache = await flags.ignoreCache;
37
-
38
- const { imsOrgId, projectId, workspaceId, workspaceName } = await initSdk({
35
+ const { imsOrgId, imsOrgCode, projectId, workspaceId, workspaceName } = await initSdk({
39
36
  ignoreCache,
40
37
  });
41
38
 
@@ -44,29 +41,32 @@ class DescribeCommand extends Command {
44
41
 
45
42
  if (meshDetails) {
46
43
  const { meshId, apiKey } = meshDetails;
44
+ const { showCloudflareURL: showEdgeMeshUrl } = await getTenantFeatures(imsOrgCode);
47
45
 
48
46
  if (meshId) {
49
- this.log('Successfully retrieved mesh details \n');
50
- this.log('Org ID: %s', imsOrgId);
51
- this.log('Project ID: %s', projectId);
52
- this.log('Workspace ID: %s', workspaceId);
53
- this.log('Mesh ID: %s', meshId);
54
-
55
- const { meshURL } = await getMesh(
47
+ const meshUrl = await buildMeshUrl(
56
48
  imsOrgId,
57
49
  projectId,
58
50
  workspaceId,
59
51
  workspaceName,
60
52
  meshId,
53
+ apiKey,
61
54
  );
62
- const meshUrl =
63
- meshURL === '' || meshURL === undefined ? MULTITENANT_GRAPHQL_SERVER_BASE_URL : meshURL;
64
55
 
65
- if (apiKey && MULTITENANT_GRAPHQL_SERVER_BASE_URL.includes(meshUrl)) {
66
- this.log('Mesh Endpoint: %s\n', `${meshUrl}/${meshId}/graphql?api_key=${apiKey}`);
56
+ this.log('Successfully retrieved mesh details \n');
57
+ this.log('Org ID: %s', imsOrgId);
58
+ this.log('Project ID: %s', projectId);
59
+ this.log('Workspace ID: %s', workspaceId);
60
+ this.log('Mesh ID: %s', meshId);
61
+
62
+ if (showEdgeMeshUrl) {
63
+ const edgeMeshUrl = buildEdgeMeshUrl(meshId, workspaceName);
64
+ this.log('Legacy Mesh Endpoint: %s', meshUrl);
65
+ this.log(chalk.bold('Edge Mesh Endpoint: %s\n'), edgeMeshUrl);
67
66
  } else {
68
- this.log('Mesh Endpoint: %s\n', `${meshUrl}/${meshId}/graphql`);
67
+ this.log('Mesh Endpoint: %s\n', meshUrl);
69
68
  }
69
+
70
70
  return meshDetails;
71
71
  } else {
72
72
  logger.error(
package/src/constants.js CHANGED
@@ -9,6 +9,7 @@ const StageConstants = {
9
9
  DEV_CONSOLE_TRANSPORTER_API_KEY: 'UDPWeb1',
10
10
  AIO_CLI_API_KEY: 'aio-cli-console-auth-stage',
11
11
  SMS_BASE_URL: 'https://graph-stage.adobe.io/api-admin',
12
+ EDGE_MESH_BASE_URL: 'https://edge-stage-graph.adobe.io/api',
12
13
  };
13
14
 
14
15
  const ProdConstants = {
@@ -18,6 +19,8 @@ const ProdConstants = {
18
19
  DEV_CONSOLE_TRANSPORTER_API_KEY: 'UDPWeb1',
19
20
  AIO_CLI_API_KEY: 'aio-cli-console-auth',
20
21
  SMS_BASE_URL: 'https://graph.adobe.io/api-admin',
22
+ EDGE_MESH_BASE_URL: 'https://edge-graph.adobe.io/api',
23
+ EDGE_MESH_SANDBOX_BASE_URL: 'https://edge-sandbox-graph.adobe.io/api',
21
24
  };
22
25
 
23
26
  const envConstants = clientEnv === 'stage' ? StageConstants : ProdConstants;
package/src/helpers.js CHANGED
@@ -423,9 +423,12 @@ async function initSdk(options) {
423
423
 
424
424
  return {
425
425
  imsOrgId: org.id,
426
+ imsOrgCode: org.code,
426
427
  projectId: project.id,
427
428
  workspaceId: workspace.id,
428
429
  workspaceName: workspace.title,
430
+ orgName: org.name,
431
+ projectName: project.title,
429
432
  };
430
433
  }
431
434
 
@@ -11,7 +11,7 @@ const util = require('util');
11
11
  const exec = util.promisify(require('child_process').exec);
12
12
  const contentDisposition = require('content-disposition');
13
13
 
14
- const { DEV_CONSOLE_TRANSPORTER_API_KEY } = CONSTANTS;
14
+ const { DEV_CONSOLE_TRANSPORTER_API_KEY, SMS_BASE_URL } = CONSTANTS;
15
15
 
16
16
  const { objToString, getDevConsoleConfig } = require('../helpers');
17
17
 
@@ -193,7 +193,15 @@ const getMesh = async (organizationId, projectId, workspaceId, workspaceName, me
193
193
  }
194
194
  };
195
195
 
196
- const createMesh = async (organizationId, projectId, workspaceId, workspaceName, data) => {
196
+ const createMesh = async (
197
+ organizationId,
198
+ projectId,
199
+ workspaceId,
200
+ workspaceName,
201
+ orgName,
202
+ projectName,
203
+ data,
204
+ ) => {
197
205
  const { baseUrl: devConsoleUrl, accessToken, apiKey } = await getDevConsoleConfig();
198
206
  const config = {
199
207
  method: 'post',
@@ -202,6 +210,9 @@ const createMesh = async (organizationId, projectId, workspaceId, workspaceName,
202
210
  'Authorization': `Bearer ${accessToken}`,
203
211
  'Content-Type': 'application/json',
204
212
  'x-request-id': global.requestId,
213
+ 'workspaceName': workspaceName,
214
+ 'orgName': orgName,
215
+ 'projectName': projectName,
205
216
  },
206
217
  data: JSON.stringify(data),
207
218
  };
@@ -821,6 +832,60 @@ const getMeshArtifact = async (organizationId, projectId, workspaceId, workspace
821
832
  }
822
833
  };
823
834
 
835
+ /**
836
+ * Gets the enabled features for the tenant.
837
+ *
838
+ * This request bypasses the Dev Console and is sent directly to the Schema Management Service.
839
+ * As a result, we provide the orgCode instead of orgId since Dev Console usually performs the translation.
840
+ * The near-term goal is to stop using Dev Console as a proxy for all routes.
841
+ * @param organizationCode
842
+ * @returns {Promise<Object>}
843
+ */
844
+ const getTenantFeatures = async organizationCode => {
845
+ const { accessToken, apiKey } = await getDevConsoleConfig();
846
+ const config = {
847
+ method: 'get',
848
+ url: `${SMS_BASE_URL}/organizations/${organizationCode}/features?API_KEY=${apiKey}`,
849
+ headers: {
850
+ 'Authorization': `Bearer ${accessToken}`,
851
+ 'x-request-id': global.requestId,
852
+ },
853
+ };
854
+
855
+ logger.info(
856
+ 'Initiating GET %s',
857
+ `${SMS_BASE_URL}/organizations/${organizationCode}/features?API_KEY=${apiKey}`,
858
+ );
859
+
860
+ try {
861
+ const response = await axios(config);
862
+
863
+ logger.info('Response from GET %s', response.status);
864
+
865
+ if (response?.status === 200) {
866
+ logger.info(`Tenant Features : ${objToString(response, ['data'])}`);
867
+
868
+ return response.data;
869
+ } else {
870
+ let errorMessage = `Something went wrong: ${objToString(
871
+ response,
872
+ ['data'],
873
+ 'Unable to get tenant features.',
874
+ )}`;
875
+ logger.error(`${errorMessage}. Received ${response.status} response instead of 200`);
876
+
877
+ throw new Error(errorMessage);
878
+ }
879
+ } catch (error) {
880
+ logger.error(`Error getting features for organization: ${organizationCode}`);
881
+
882
+ return {
883
+ imsOrgId: organizationCode,
884
+ showCloudflareURL: false,
885
+ };
886
+ }
887
+ };
888
+
824
889
  module.exports = {
825
890
  getApiKeyCredential,
826
891
  describeMesh,
@@ -835,4 +900,5 @@ module.exports = {
835
900
  subscribeCredentialToMeshService,
836
901
  unsubscribeCredentialFromMeshService,
837
902
  getMeshArtifact,
903
+ getTenantFeatures,
838
904
  };
@@ -0,0 +1,58 @@
1
+ const CONSTANTS = require('./constants');
2
+ const { getMesh } = require('./lib/devConsole');
3
+
4
+ const {
5
+ MULTITENANT_GRAPHQL_SERVER_BASE_URL,
6
+ EDGE_MESH_BASE_URL,
7
+ EDGE_MESH_SANDBOX_BASE_URL,
8
+ } = CONSTANTS;
9
+
10
+ /**
11
+ * Build the mesh url for the multitenant mesh.
12
+ *
13
+ * Gets the mesh details to checks for a custom domain in the case of a TI mesh.
14
+ * @param imsOrgId
15
+ * @param projectId
16
+ * @param workspaceId
17
+ * @param workspaceName
18
+ * @param meshId
19
+ * @param apiKey
20
+ * @returns {Promise<string>}
21
+ */
22
+ async function buildMeshUrl(imsOrgId, projectId, workspaceId, workspaceName, meshId, apiKey) {
23
+ const { meshURL: customBaseUrl } = await getMesh(
24
+ imsOrgId,
25
+ projectId,
26
+ workspaceId,
27
+ workspaceName,
28
+ meshId,
29
+ );
30
+
31
+ return customBaseUrl
32
+ ? `${customBaseUrl}/${meshId}/graphql`
33
+ : `${MULTITENANT_GRAPHQL_SERVER_BASE_URL}/${meshId}/graphql${
34
+ apiKey ? `?api_key=${apiKey}` : ''
35
+ }`;
36
+ }
37
+
38
+ /**
39
+ * Builds the mesh url for the edge mesh.
40
+ *
41
+ * Uses the url for the appropriate Cloudflare namespace based on the console workspace name.
42
+ * @param meshId
43
+ * @param workspaceName
44
+ * @returns {string}
45
+ */
46
+ function buildEdgeMeshUrl(meshId, workspaceName) {
47
+ let baseUrl;
48
+
49
+ if (EDGE_MESH_BASE_URL.includes('stage')) {
50
+ baseUrl = EDGE_MESH_BASE_URL;
51
+ } else {
52
+ baseUrl = workspaceName === 'Production' ? EDGE_MESH_BASE_URL : EDGE_MESH_SANDBOX_BASE_URL;
53
+ }
54
+
55
+ return `${baseUrl}/${meshId}/graphql`;
56
+ }
57
+
58
+ module.exports = { buildMeshUrl, buildEdgeMeshUrl };