@adobe/aio-cli-plugin-api-mesh 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/oclif.manifest.json +1 -1
- package/package.json +4 -3
- package/src/commands/__fixtures__/env_invalid +8 -0
- package/src/commands/__fixtures__/env_valid +3 -0
- package/src/commands/__fixtures__/sample_mesh_with_placeholder +17 -0
- package/src/commands/api-mesh/__tests__/create.test.js +351 -131
- package/src/commands/api-mesh/__tests__/delete.test.js +3 -3
- package/src/commands/api-mesh/__tests__/update.test.js +128 -128
- package/src/commands/api-mesh/create.js +69 -5
- package/src/commands/api-mesh/update.js +69 -5
- package/src/helpers.js +110 -0
- package/src/meshInterpolation.js +120 -0
- package/src/utils.js +8 -2
|
@@ -73,134 +73,6 @@ describe('update command tests', () => {
|
|
|
73
73
|
});
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
-
afterEach(() => {
|
|
77
|
-
jest.restoreAllMocks();
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
test('should fail if mesh id is missing', async () => {
|
|
81
|
-
getMeshId.mockResolvedValue(null);
|
|
82
|
-
const runResult = UpdateCommand.run();
|
|
83
|
-
|
|
84
|
-
await expect(runResult).rejects.toMatchInlineSnapshot(
|
|
85
|
-
`[Error: Unable to update. No mesh found for Org(1234) -> Project(5678) -> Workspace(123456789). Please check the details and try again.]`,
|
|
86
|
-
);
|
|
87
|
-
expect(logSpy.mock.calls).toMatchInlineSnapshot(`[]`);
|
|
88
|
-
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
|
|
89
|
-
[
|
|
90
|
-
[
|
|
91
|
-
"Unable to update. No mesh found for Org(1234) -> Project(5678) -> Workspace(123456789). Please check the details and try again.",
|
|
92
|
-
],
|
|
93
|
-
]
|
|
94
|
-
`);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test('should fail if getMeshId api failed', async () => {
|
|
98
|
-
getMeshId.mockRejectedValue(new Error('getMeshId api failed'));
|
|
99
|
-
const runResult = UpdateCommand.run();
|
|
100
|
-
|
|
101
|
-
await expect(runResult).rejects.toMatchInlineSnapshot(
|
|
102
|
-
`[Error: Unable to get mesh ID. Please check the details and try again. RequestId: dummy_request_id]`,
|
|
103
|
-
);
|
|
104
|
-
expect(logSpy.mock.calls).toMatchInlineSnapshot(`[]`);
|
|
105
|
-
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
|
|
106
|
-
[
|
|
107
|
-
[
|
|
108
|
-
"Unable to get mesh ID. Please check the details and try again. RequestId: dummy_request_id",
|
|
109
|
-
],
|
|
110
|
-
]
|
|
111
|
-
`);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
test('should fail if update file path is missing', async () => {
|
|
115
|
-
parseSpy.mockResolvedValueOnce({
|
|
116
|
-
args: { file: null },
|
|
117
|
-
flags: {
|
|
118
|
-
ignoreCache: mockIgnoreCacheFlag,
|
|
119
|
-
autoConfirmAction: mockAutoApproveAction,
|
|
120
|
-
},
|
|
121
|
-
});
|
|
122
|
-
const runResult = UpdateCommand.run();
|
|
123
|
-
|
|
124
|
-
await expect(runResult).rejects.toEqual(
|
|
125
|
-
new Error('Missing required args. Run aio api-mesh update --help for more info.'),
|
|
126
|
-
);
|
|
127
|
-
expect(logSpy.mock.calls).toMatchInlineSnapshot(`[]`);
|
|
128
|
-
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
|
|
129
|
-
[
|
|
130
|
-
[
|
|
131
|
-
"Missing required args. Run aio api-mesh update --help for more info.",
|
|
132
|
-
],
|
|
133
|
-
]
|
|
134
|
-
`);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
test('should fail if dummy file path is provided', async () => {
|
|
138
|
-
readFile.mockRejectedValueOnce(new Error('File not found'));
|
|
139
|
-
const runResult = UpdateCommand.run();
|
|
140
|
-
|
|
141
|
-
await expect(runResult).rejects.toEqual(
|
|
142
|
-
new Error(
|
|
143
|
-
'Unable to read the mesh configuration file provided. Please check the file and try again.',
|
|
144
|
-
),
|
|
145
|
-
);
|
|
146
|
-
expect(logSpy.mock.calls).toMatchInlineSnapshot(`
|
|
147
|
-
[
|
|
148
|
-
[
|
|
149
|
-
"File not found",
|
|
150
|
-
],
|
|
151
|
-
]
|
|
152
|
-
`);
|
|
153
|
-
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
|
|
154
|
-
[
|
|
155
|
-
[
|
|
156
|
-
"Unable to read the mesh configuration file provided. Please check the file and try again.",
|
|
157
|
-
],
|
|
158
|
-
]
|
|
159
|
-
`);
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
test('should not update if user prompt returns false', async () => {
|
|
163
|
-
promptConfirm.mockResolvedValueOnce(false);
|
|
164
|
-
|
|
165
|
-
const runResult = await UpdateCommand.run();
|
|
166
|
-
|
|
167
|
-
expect(runResult).toMatchInlineSnapshot(`"Update cancelled"`);
|
|
168
|
-
expect(logSpy.mock.calls).toMatchInlineSnapshot(`
|
|
169
|
-
[
|
|
170
|
-
[
|
|
171
|
-
"Update cancelled",
|
|
172
|
-
],
|
|
173
|
-
]
|
|
174
|
-
`);
|
|
175
|
-
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`[]`);
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
test('should fail if updateMesh method failed', async () => {
|
|
179
|
-
updateMesh.mockRejectedValueOnce(new Error('dummy_error'));
|
|
180
|
-
|
|
181
|
-
const runResult = UpdateCommand.run();
|
|
182
|
-
|
|
183
|
-
await expect(runResult).rejects.toEqual(
|
|
184
|
-
new Error(
|
|
185
|
-
'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',
|
|
186
|
-
),
|
|
187
|
-
);
|
|
188
|
-
expect(logSpy.mock.calls).toMatchInlineSnapshot(`
|
|
189
|
-
[
|
|
190
|
-
[
|
|
191
|
-
"dummy_error",
|
|
192
|
-
],
|
|
193
|
-
]
|
|
194
|
-
`);
|
|
195
|
-
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
|
|
196
|
-
[
|
|
197
|
-
[
|
|
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
|
-
],
|
|
200
|
-
]
|
|
201
|
-
`);
|
|
202
|
-
});
|
|
203
|
-
|
|
204
76
|
test('should pass with valid args', async () => {
|
|
205
77
|
const runResult = await UpdateCommand.run();
|
|
206
78
|
|
|
@@ -322,4 +194,132 @@ describe('update command tests', () => {
|
|
|
322
194
|
`);
|
|
323
195
|
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`[]`);
|
|
324
196
|
});
|
|
197
|
+
|
|
198
|
+
test('should fail if mesh id is missing', async () => {
|
|
199
|
+
getMeshId.mockResolvedValue(null);
|
|
200
|
+
const runResult = UpdateCommand.run();
|
|
201
|
+
|
|
202
|
+
await expect(runResult).rejects.toMatchInlineSnapshot(
|
|
203
|
+
`[Error: Unable to update. No mesh found for Org(1234) -> Project(5678) -> Workspace(123456789). Please check the details and try again.]`,
|
|
204
|
+
);
|
|
205
|
+
expect(logSpy.mock.calls).toMatchInlineSnapshot(`[]`);
|
|
206
|
+
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
|
|
207
|
+
[
|
|
208
|
+
[
|
|
209
|
+
"Unable to update. No mesh found for Org(1234) -> Project(5678) -> Workspace(123456789). Please check the details and try again.",
|
|
210
|
+
],
|
|
211
|
+
]
|
|
212
|
+
`);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
test('should fail if getMeshId api failed', async () => {
|
|
216
|
+
getMeshId.mockRejectedValue(new Error('getMeshId api failed'));
|
|
217
|
+
const runResult = UpdateCommand.run();
|
|
218
|
+
|
|
219
|
+
await expect(runResult).rejects.toMatchInlineSnapshot(
|
|
220
|
+
`[Error: Unable to get mesh ID. Please check the details and try again. RequestId: dummy_request_id]`,
|
|
221
|
+
);
|
|
222
|
+
expect(logSpy.mock.calls).toMatchInlineSnapshot(`[]`);
|
|
223
|
+
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
|
|
224
|
+
[
|
|
225
|
+
[
|
|
226
|
+
"Unable to get mesh ID. Please check the details and try again. RequestId: dummy_request_id",
|
|
227
|
+
],
|
|
228
|
+
]
|
|
229
|
+
`);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
test('should fail if updateMesh method failed', async () => {
|
|
233
|
+
updateMesh.mockRejectedValueOnce(new Error('dummy_error'));
|
|
234
|
+
|
|
235
|
+
const runResult = UpdateCommand.run();
|
|
236
|
+
|
|
237
|
+
// await expect(runResult).rejects.toEqual(
|
|
238
|
+
// new Error(
|
|
239
|
+
// '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',
|
|
240
|
+
// ),
|
|
241
|
+
// );
|
|
242
|
+
|
|
243
|
+
await expect(runResult).rejects.toMatchInlineSnapshot(
|
|
244
|
+
`[Error: 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]`,
|
|
245
|
+
);
|
|
246
|
+
expect(logSpy.mock.calls).toMatchInlineSnapshot(`
|
|
247
|
+
[
|
|
248
|
+
[
|
|
249
|
+
"dummy_error",
|
|
250
|
+
],
|
|
251
|
+
]
|
|
252
|
+
`);
|
|
253
|
+
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
|
|
254
|
+
[
|
|
255
|
+
[
|
|
256
|
+
"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",
|
|
257
|
+
],
|
|
258
|
+
]
|
|
259
|
+
`);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
test('should fail if update file path is missing', async () => {
|
|
263
|
+
parseSpy.mockResolvedValueOnce({
|
|
264
|
+
args: { file: null },
|
|
265
|
+
flags: {
|
|
266
|
+
ignoreCache: mockIgnoreCacheFlag,
|
|
267
|
+
autoConfirmAction: mockAutoApproveAction,
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
const runResult = UpdateCommand.run();
|
|
271
|
+
|
|
272
|
+
await expect(runResult).rejects.toEqual(
|
|
273
|
+
new Error('Missing required args. Run aio api-mesh update --help for more info.'),
|
|
274
|
+
);
|
|
275
|
+
expect(logSpy.mock.calls).toMatchInlineSnapshot(`[]`);
|
|
276
|
+
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
|
|
277
|
+
[
|
|
278
|
+
[
|
|
279
|
+
"Missing required args. Run aio api-mesh update --help for more info.",
|
|
280
|
+
],
|
|
281
|
+
]
|
|
282
|
+
`);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
test('should fail if dummy file path is provided', async () => {
|
|
286
|
+
readFile.mockRejectedValueOnce(new Error('File not found'));
|
|
287
|
+
const runResult = UpdateCommand.run();
|
|
288
|
+
|
|
289
|
+
await expect(runResult).rejects.toEqual(
|
|
290
|
+
new Error(
|
|
291
|
+
'Unable to read the mesh configuration file provided. Please check the file and try again.',
|
|
292
|
+
),
|
|
293
|
+
);
|
|
294
|
+
expect(logSpy.mock.calls).toMatchInlineSnapshot(`
|
|
295
|
+
[
|
|
296
|
+
[
|
|
297
|
+
"File not found",
|
|
298
|
+
],
|
|
299
|
+
]
|
|
300
|
+
`);
|
|
301
|
+
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
|
|
302
|
+
[
|
|
303
|
+
[
|
|
304
|
+
"Unable to read the mesh configuration file provided. Please check the file and try again.",
|
|
305
|
+
],
|
|
306
|
+
]
|
|
307
|
+
`);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
test('should not update if user prompt returns false', async () => {
|
|
311
|
+
promptConfirm.mockResolvedValueOnce(false);
|
|
312
|
+
|
|
313
|
+
const runResult = await UpdateCommand.run();
|
|
314
|
+
|
|
315
|
+
expect(runResult).toMatchInlineSnapshot(`"Update cancelled"`);
|
|
316
|
+
expect(logSpy.mock.calls).toMatchInlineSnapshot(`
|
|
317
|
+
[
|
|
318
|
+
[
|
|
319
|
+
"Update cancelled",
|
|
320
|
+
],
|
|
321
|
+
]
|
|
322
|
+
`);
|
|
323
|
+
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`[]`);
|
|
324
|
+
});
|
|
325
325
|
});
|
|
@@ -15,14 +15,16 @@ const { readFile } = require('fs/promises');
|
|
|
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, jsonFlag } = require('../../utils');
|
|
18
|
+
const { ignoreCacheFlag, autoConfirmActionFlag, jsonFlag, envFileFlag } = require('../../utils');
|
|
19
19
|
const {
|
|
20
20
|
createMesh,
|
|
21
21
|
createAPIMeshCredentials,
|
|
22
22
|
subscribeCredentialToMeshService,
|
|
23
23
|
} = require('../../lib/devConsole');
|
|
24
24
|
|
|
25
|
-
require('
|
|
25
|
+
const meshInterpolation = require('../../meshInterpolation');
|
|
26
|
+
|
|
27
|
+
const dotenv = require('dotenv');
|
|
26
28
|
|
|
27
29
|
const { MULTITENANT_GRAPHQL_SERVER_BASE_URL } = CONSTANTS;
|
|
28
30
|
|
|
@@ -32,6 +34,7 @@ class CreateCommand extends Command {
|
|
|
32
34
|
ignoreCache: ignoreCacheFlag,
|
|
33
35
|
autoConfirmAction: autoConfirmActionFlag,
|
|
34
36
|
json: jsonFlag,
|
|
37
|
+
env: envFileFlag,
|
|
35
38
|
};
|
|
36
39
|
|
|
37
40
|
static enableJsonFlag = true;
|
|
@@ -51,15 +54,16 @@ class CreateCommand extends Command {
|
|
|
51
54
|
|
|
52
55
|
const ignoreCache = await flags.ignoreCache;
|
|
53
56
|
const autoConfirmAction = await flags.autoConfirmAction;
|
|
54
|
-
|
|
57
|
+
const envFilePath=await flags.env;
|
|
55
58
|
const { imsOrgId, projectId, workspaceId } = await initSdk({
|
|
56
59
|
ignoreCache,
|
|
57
60
|
});
|
|
58
61
|
|
|
59
|
-
let
|
|
62
|
+
let inputMeshData;
|
|
60
63
|
|
|
64
|
+
//Input the mesh data from the input file
|
|
61
65
|
try {
|
|
62
|
-
|
|
66
|
+
inputMeshData = await readFile(args.file, 'utf8');
|
|
63
67
|
} catch (error) {
|
|
64
68
|
logger.error(error);
|
|
65
69
|
|
|
@@ -69,6 +73,66 @@ class CreateCommand extends Command {
|
|
|
69
73
|
);
|
|
70
74
|
}
|
|
71
75
|
|
|
76
|
+
let data;
|
|
77
|
+
|
|
78
|
+
if (envFilePath) {
|
|
79
|
+
let envFileContent;
|
|
80
|
+
|
|
81
|
+
//Read the environment file
|
|
82
|
+
try {
|
|
83
|
+
envFileContent = await readFile(envFilePath, 'utf8');
|
|
84
|
+
} catch (error) {
|
|
85
|
+
this.log(error.message);
|
|
86
|
+
this.error('Unable to read the env file provided. Please check the file and try again.');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
//Validate the env file
|
|
90
|
+
const envFileValidity = meshInterpolation.validateEnvFileFormat(envFileContent);
|
|
91
|
+
if (envFileValidity.valid) {
|
|
92
|
+
//load env file into the process.env object
|
|
93
|
+
meshInterpolation.clearEnv();
|
|
94
|
+
|
|
95
|
+
//Added env at start of each environment variable
|
|
96
|
+
const envObj = { env: dotenv.config({ path: envFilePath }).parsed };
|
|
97
|
+
|
|
98
|
+
let {
|
|
99
|
+
interpolationStatus,
|
|
100
|
+
missingKeys,
|
|
101
|
+
interpolatedMeshData,
|
|
102
|
+
} = await meshInterpolation.interpolateMesh(inputMeshData, envObj);
|
|
103
|
+
|
|
104
|
+
//De-duplicate the missing keys array
|
|
105
|
+
missingKeys = missingKeys.filter(function (item, index, inputArray) {
|
|
106
|
+
return inputArray.indexOf(item) == index;
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
if (interpolationStatus == 'failed') {
|
|
110
|
+
this.error(
|
|
111
|
+
'The mesh file cannot be interpolated due to missing keys : ' + missingKeys.toString(),
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
data = JSON.parse(interpolatedMeshData);
|
|
117
|
+
} catch (err) {
|
|
118
|
+
this.log(err.message);
|
|
119
|
+
this.log(interpolatedMeshData);
|
|
120
|
+
this.error(
|
|
121
|
+
'Interpolated mesh is not a valid JSON. Please check the generated json file.',
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
this.error(`Issue in ${envFilePath} file - ` + envFileValidity.error);
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
try {
|
|
129
|
+
data = JSON.parse(inputMeshData);
|
|
130
|
+
} catch (err) {
|
|
131
|
+
this.log(err.message);
|
|
132
|
+
this.error('Input mesh file is not a valid JSON. Please check the file provided.');
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
72
136
|
let shouldContinue = true;
|
|
73
137
|
|
|
74
138
|
if (!autoConfirmAction) {
|
|
@@ -14,16 +14,18 @@ const { readFile } = require('fs/promises');
|
|
|
14
14
|
|
|
15
15
|
const logger = require('../../classes/logger');
|
|
16
16
|
const { initSdk, initRequestId, promptConfirm } = require('../../helpers');
|
|
17
|
-
const { ignoreCacheFlag, autoConfirmActionFlag } = require('../../utils');
|
|
17
|
+
const { ignoreCacheFlag, autoConfirmActionFlag, envFileFlag } = require('../../utils');
|
|
18
18
|
const { getMeshId, updateMesh } = require('../../lib/devConsole');
|
|
19
|
+
const meshInterpolation = require('../../meshInterpolation');
|
|
19
20
|
|
|
20
|
-
require('dotenv')
|
|
21
|
+
const dotenv = require('dotenv');
|
|
21
22
|
|
|
22
23
|
class UpdateCommand extends Command {
|
|
23
24
|
static args = [{ name: 'file' }];
|
|
24
25
|
static flags = {
|
|
25
26
|
ignoreCache: ignoreCacheFlag,
|
|
26
27
|
autoConfirmAction: autoConfirmActionFlag,
|
|
28
|
+
env: envFileFlag,
|
|
27
29
|
};
|
|
28
30
|
|
|
29
31
|
async run() {
|
|
@@ -41,15 +43,17 @@ class UpdateCommand extends Command {
|
|
|
41
43
|
|
|
42
44
|
const ignoreCache = await flags.ignoreCache;
|
|
43
45
|
const autoConfirmAction = await flags.autoConfirmAction;
|
|
46
|
+
const envFilePath=await flags.env;
|
|
44
47
|
|
|
45
48
|
const { imsOrgId, projectId, workspaceId } = await initSdk({
|
|
46
49
|
ignoreCache,
|
|
47
50
|
});
|
|
48
51
|
|
|
49
|
-
let
|
|
52
|
+
let inputMeshData;
|
|
50
53
|
|
|
54
|
+
//Input the mesh data from the input file
|
|
51
55
|
try {
|
|
52
|
-
|
|
56
|
+
inputMeshData = await readFile(args.file, 'utf8');
|
|
53
57
|
} catch (error) {
|
|
54
58
|
logger.error(error);
|
|
55
59
|
|
|
@@ -59,7 +63,7 @@ class UpdateCommand extends Command {
|
|
|
59
63
|
);
|
|
60
64
|
}
|
|
61
65
|
|
|
62
|
-
let meshId
|
|
66
|
+
let meshId;
|
|
63
67
|
|
|
64
68
|
try {
|
|
65
69
|
meshId = await getMeshId(imsOrgId, projectId, workspaceId);
|
|
@@ -69,6 +73,66 @@ class UpdateCommand extends Command {
|
|
|
69
73
|
);
|
|
70
74
|
}
|
|
71
75
|
|
|
76
|
+
let data;
|
|
77
|
+
|
|
78
|
+
if (envFilePath) {
|
|
79
|
+
let envFileContent;
|
|
80
|
+
|
|
81
|
+
//Read the environment file
|
|
82
|
+
try {
|
|
83
|
+
envFileContent = await readFile(envFilePath, 'utf8');
|
|
84
|
+
} catch (error) {
|
|
85
|
+
this.log(error.message);
|
|
86
|
+
this.error('Unable to read the env file provided. Please check the file and try again.');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
//Validate the env file
|
|
90
|
+
const envFileValidity = meshInterpolation.validateEnvFileFormat(envFileContent);
|
|
91
|
+
if (envFileValidity.valid) {
|
|
92
|
+
//load env file into the process.env object
|
|
93
|
+
meshInterpolation.clearEnv();
|
|
94
|
+
|
|
95
|
+
//Added env at start of each environment variable
|
|
96
|
+
const envObj = { env: dotenv.config({ path: envFilePath }).parsed };
|
|
97
|
+
|
|
98
|
+
let {
|
|
99
|
+
interpolationStatus,
|
|
100
|
+
missingKeys,
|
|
101
|
+
interpolatedMeshData,
|
|
102
|
+
} = await meshInterpolation.interpolateMesh(inputMeshData, envObj);
|
|
103
|
+
|
|
104
|
+
//De-duplicate the missing keys array
|
|
105
|
+
missingKeys = missingKeys.filter(function (item, index, inputArray) {
|
|
106
|
+
return inputArray.indexOf(item) == index;
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
if (interpolationStatus == 'failed') {
|
|
110
|
+
this.error(
|
|
111
|
+
'The mesh file cannot be interpolated due to missing keys : ' + missingKeys.toString(),
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
data = JSON.parse(interpolatedMeshData);
|
|
117
|
+
} catch (err) {
|
|
118
|
+
this.log(err.message);
|
|
119
|
+
this.log(interpolatedMeshData);
|
|
120
|
+
this.error(
|
|
121
|
+
'Interpolated mesh is not a valid JSON. Please check the generated json file.',
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
this.error(`Issue in ${envFilePath} file - ` + envFileValidity.error);
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
try {
|
|
129
|
+
data = JSON.parse(inputMeshData);
|
|
130
|
+
} catch (err) {
|
|
131
|
+
this.log(err.message);
|
|
132
|
+
this.error('Input mesh file is not a valid JSON. Please check the input file provided.');
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
72
136
|
if (meshId) {
|
|
73
137
|
let shouldContinue = true;
|
|
74
138
|
|
package/src/helpers.js
CHANGED
|
@@ -459,6 +459,112 @@ async function promptInput(message) {
|
|
|
459
459
|
return selected.item;
|
|
460
460
|
}
|
|
461
461
|
|
|
462
|
+
function clearEnv() {
|
|
463
|
+
for (const key in process.env) {
|
|
464
|
+
delete process.env[key];
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function lintEnvFileContent(envContent) {
|
|
469
|
+
//Key should start with a underscore or an alphabet followed by underscore/alphanumeric characters
|
|
470
|
+
const envKeyRegex = /^[a-zA-Z_]+[a-zA-Z0-9_]*$/;
|
|
471
|
+
|
|
472
|
+
const envValueRegex = /^(?:"(?:\\.|[^\\"])*"|'(?:\\.|[^\\'])*'|[^'"\s])+$/;
|
|
473
|
+
|
|
474
|
+
/*
|
|
475
|
+
The above regex matches one or more of below :
|
|
476
|
+
(?:"(?:\\.|[^\\"])*"|'(?:\\.|[^\\'])*'|[^'"\s])
|
|
477
|
+
which is
|
|
478
|
+
1. ?:"(?:\\.|[^\\"])*" : Non capturing group starts and ends with '"'
|
|
479
|
+
*/
|
|
480
|
+
const envDict = {};
|
|
481
|
+
const lines = envContent.split(/\r?\n/);
|
|
482
|
+
const errors = [];
|
|
483
|
+
|
|
484
|
+
for (let index = 0; index < lines.length; index++) {
|
|
485
|
+
const line = lines[index];
|
|
486
|
+
const trimmedLine = line.trim();
|
|
487
|
+
if (trimmedLine.startsWith('#') || trimmedLine === '') {
|
|
488
|
+
// ignore comment or empty lines
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
if (!trimmedLine.includes('=')) {
|
|
493
|
+
errors.push(`Invalid format << ${trimmedLine} >> on line ${index + 1}`);
|
|
494
|
+
} else {
|
|
495
|
+
const [key, value] = trimmedLine.split('=', 2);
|
|
496
|
+
if (!envKeyRegex.test(key) || !envValueRegex.test(value)) {
|
|
497
|
+
// invalid format: key or value does not match regex
|
|
498
|
+
errors.push(`Invalid format for key/value << ${trimmedLine} >> on line ${index + 1}`);
|
|
499
|
+
}
|
|
500
|
+
if (key in envDict) {
|
|
501
|
+
// duplicate key found
|
|
502
|
+
errors.push(`Duplicate key << ${key} >> on line ${index + 1}`);
|
|
503
|
+
}
|
|
504
|
+
envDict[key] = value;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
if (errors.length) {
|
|
508
|
+
return {
|
|
509
|
+
valid: false,
|
|
510
|
+
error: errors.toString(),
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
return {
|
|
514
|
+
valid: true,
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
async function loadPupa() {
|
|
519
|
+
try {
|
|
520
|
+
const pupa = (await import('pupa')).default;
|
|
521
|
+
return pupa;
|
|
522
|
+
} catch {
|
|
523
|
+
console.log('Error while loading pupa module');
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
async function interpolateMesh(data, obj) {
|
|
528
|
+
let missingKeys = [];
|
|
529
|
+
let interpolatedMesh;
|
|
530
|
+
await loadPupa().then(pupa => {
|
|
531
|
+
interpolatedMesh = pupa(data, obj, {
|
|
532
|
+
ignoreMissing: true,
|
|
533
|
+
transform: ({ value, key }) => {
|
|
534
|
+
if (key.startsWith('env.')) {
|
|
535
|
+
if (value) {
|
|
536
|
+
return value;
|
|
537
|
+
} else {
|
|
538
|
+
// missing value, add to list
|
|
539
|
+
missingKeys.push(key.split('.')[1]);
|
|
540
|
+
}
|
|
541
|
+
} else {
|
|
542
|
+
//ignore
|
|
543
|
+
return undefined;
|
|
544
|
+
}
|
|
545
|
+
return value;
|
|
546
|
+
},
|
|
547
|
+
});
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
if (missingKeys.length) {
|
|
551
|
+
return {
|
|
552
|
+
interpolationStatus: 'failed',
|
|
553
|
+
missingKeys: missingKeys,
|
|
554
|
+
interpolatedMesh: '',
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
return {
|
|
558
|
+
interpolationStatus: 'success',
|
|
559
|
+
missingKeys: [],
|
|
560
|
+
interpolatedMesh: interpolatedMesh,
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
async function getname(name, length) {
|
|
565
|
+
return { name: name, length: length };
|
|
566
|
+
}
|
|
567
|
+
|
|
462
568
|
module.exports = {
|
|
463
569
|
promptInput,
|
|
464
570
|
promptConfirm,
|
|
@@ -468,4 +574,8 @@ module.exports = {
|
|
|
468
574
|
initRequestId,
|
|
469
575
|
promptSelect,
|
|
470
576
|
promptMultiselect,
|
|
577
|
+
clearEnv,
|
|
578
|
+
lintEnvFileContent,
|
|
579
|
+
interpolateMesh,
|
|
580
|
+
getname,
|
|
471
581
|
};
|