@adobe/aio-cli-plugin-api-mesh 2.2.0 → 2.2.1

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.
Files changed (33) hide show
  1. package/oclif.manifest.json +1 -1
  2. package/package.json +2 -1
  3. package/src/commands/__fixtures__/files/requestParams.json +3 -0
  4. package/src/commands/__fixtures__/openapi-schema.json +4 -0
  5. package/src/commands/__fixtures__/requestParams.json +3 -0
  6. package/src/commands/__fixtures__/sample_fully_qualified_mesh.json +29 -0
  7. package/src/commands/__fixtures__/sample_invalid_mesh.txt +17 -0
  8. package/src/commands/__fixtures__/sample_mesh_files.json +23 -0
  9. package/src/commands/__fixtures__/sample_mesh_invalid_file_content.json +14 -0
  10. package/src/commands/__fixtures__/sample_mesh_invalid_file_name.json +27 -0
  11. package/src/commands/__fixtures__/sample_mesh_invalid_paths.json +23 -0
  12. package/src/commands/__fixtures__/sample_mesh_invalid_type.json +27 -0
  13. package/src/commands/__fixtures__/sample_mesh_mismatching_path.json +29 -0
  14. package/src/commands/__fixtures__/sample_mesh_outside_workspace_dir.json +23 -0
  15. package/src/commands/__fixtures__/sample_mesh_path_from_home.json +14 -0
  16. package/src/commands/__fixtures__/sample_mesh_subdirectory.json +23 -0
  17. package/src/commands/__fixtures__/sample_mesh_with_files_array.json +29 -0
  18. package/src/commands/api-mesh/__tests__/create.test.js +1000 -31
  19. package/src/commands/api-mesh/__tests__/get.test.js +8 -0
  20. package/src/commands/api-mesh/__tests__/init.test.js +390 -0
  21. package/src/commands/api-mesh/__tests__/update.test.js +419 -4
  22. package/src/commands/api-mesh/create.js +37 -68
  23. package/src/commands/api-mesh/get.js +7 -2
  24. package/src/commands/api-mesh/init.js +168 -0
  25. package/src/commands/api-mesh/source/__tests__/get.test.js +1 -1
  26. package/src/commands/api-mesh/source/__tests__/install.test.js +2 -2
  27. package/src/commands/api-mesh/update.js +35 -67
  28. package/src/helpers.js +249 -91
  29. package/src/lib/devConsole.js +1 -2
  30. package/src/templates/gitignore +1 -0
  31. package/src/templates/package.json +38 -0
  32. package/src/utils.js +329 -31
  33. package/src/meshInterpolation.js +0 -120
@@ -0,0 +1,168 @@
1
+ /*
2
+ Copyright 2021 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ Unless required by applicable law or agreed to in writing, software distributed under
7
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
8
+ OF ANY KIND, either express or implied. See the License for the specific language
9
+ governing permissions and limitations under the License.
10
+ */
11
+
12
+ const { Command, Flags } = require('@oclif/core');
13
+ const resolve = require('path').resolve;
14
+
15
+ const { promptConfirm, promptSelect, runCliCommand } = require('../../helpers');
16
+ const { getAppRootDir } = require('../../utils');
17
+
18
+ const fs = require('fs/promises');
19
+
20
+ class InitCommand extends Command {
21
+ static summary = 'Initiate API Mesh workspace';
22
+ static description =
23
+ 'This command will create a workspace where you can organise your API mesh configuration and other files';
24
+
25
+ static args = [
26
+ {
27
+ name: 'projectName',
28
+ required: true,
29
+ description: 'Project name',
30
+ },
31
+ ];
32
+
33
+ static flags = {
34
+ path: Flags.string({
35
+ char: 'p',
36
+ summary: 'workspace path',
37
+ default: '.',
38
+ }),
39
+ packageManager: Flags.string({
40
+ char: 'm',
41
+ summary: 'select yarn or npm for package management',
42
+ options: ['npm', 'yarn'],
43
+ }),
44
+ git: Flags.string({
45
+ char: 'g',
46
+ summary: 'Should the workspace be initiated as a git project.',
47
+ options: ['y', 'n'],
48
+ }),
49
+ };
50
+
51
+ static enableJsonFlag = true;
52
+
53
+ static examples = [
54
+ {
55
+ description: 'API mesh workspace init',
56
+ command: 'aio api-mesh init commerce-mesh',
57
+ },
58
+ {
59
+ description: 'API mesh workspace init with flags',
60
+ command:
61
+ 'aio api-mesh init commerce-mesh --path ./mesh_projects/test_mesh --git y --packageManager yarn',
62
+ },
63
+ ];
64
+
65
+ async createPackageJson(templatePath, filePath, projectTitle = 'api-mesh-starter') {
66
+ const template = await fs.readFile(templatePath, 'utf8');
67
+
68
+ const pkgJSON = { ...JSON.parse(template), name: projectTitle };
69
+
70
+ await fs.writeFile(filePath, JSON.stringify(pkgJSON, null, 2), 'utf8', { mode: 'w' });
71
+ }
72
+
73
+ async run() {
74
+ const { args, flags } = await this.parse(InitCommand);
75
+ const gitFlagOptions = {
76
+ y: true,
77
+ n: false,
78
+ };
79
+
80
+ let absolutePath = resolve(flags.path);
81
+ let shouldCreateGit = gitFlagOptions[flags.git];
82
+ let packageManagerChoice = flags.packageManager;
83
+ const packageJsonTemplate = `${getAppRootDir()}/src/templates/package.json`;
84
+ const shouldCreateWorkspace = await promptConfirm(
85
+ `Do you want to create the workspace in ${absolutePath}`,
86
+ );
87
+
88
+ if (shouldCreateWorkspace) {
89
+ if (shouldCreateGit === undefined) {
90
+ shouldCreateGit = await promptConfirm(`Do you want to initiate git in your workspace?`);
91
+ }
92
+
93
+ if (packageManagerChoice === undefined) {
94
+ packageManagerChoice = await promptSelect(`Select a package manager`, [
95
+ { name: 'npm', value: 'npm' },
96
+ { name: 'yarn', value: 'yarn' },
97
+ ]);
98
+ }
99
+
100
+ try {
101
+ await fs.access(absolutePath);
102
+ if (
103
+ !(await promptConfirm(
104
+ 'The directory is not empty. Do you want to create a sub directory with project name',
105
+ ))
106
+ ) {
107
+ return;
108
+ }
109
+ absolutePath += '/' + args.projectName;
110
+ } catch (err) {
111
+ // No action needed
112
+ }
113
+
114
+ this.log(`Creating workspace in ${absolutePath}`);
115
+
116
+ try {
117
+ await fs.mkdir(absolutePath);
118
+ } catch (error) {
119
+ this.error(`Could not create directory ${error.message}`);
120
+ }
121
+
122
+ if (shouldCreateGit) {
123
+ this.log('Initiating git in workspace');
124
+ try {
125
+ await runCliCommand('git init', absolutePath);
126
+
127
+ const gitIgnoreTemplate = `${getAppRootDir()}/src/templates/gitignore`;
128
+
129
+ await fs.writeFile(`${absolutePath}/.gitignore`, gitIgnoreTemplate, 'utf8', {
130
+ mode: 'w',
131
+ });
132
+ } catch (error) {
133
+ this.error(error);
134
+ }
135
+ }
136
+
137
+ await fs.writeFile(`${absolutePath}/.env`, '', 'utf8', { mode: 'w' });
138
+
139
+ this.log(`Installing dependencies`);
140
+
141
+ await this.createPackageJson(
142
+ packageJsonTemplate,
143
+ `${absolutePath}/package.json`,
144
+ args.projectName,
145
+ );
146
+
147
+ if (packageManagerChoice === 'npm') {
148
+ try {
149
+ await runCliCommand(`npm install`, absolutePath);
150
+ } catch (error) {
151
+ this.error(error);
152
+ }
153
+ }
154
+
155
+ if (packageManagerChoice === 'yarn') {
156
+ try {
157
+ await runCliCommand(`yarn install`, absolutePath);
158
+ } catch (error) {
159
+ this.error(error);
160
+ }
161
+ }
162
+
163
+ this.log('Local workspace created successfully');
164
+ }
165
+ }
166
+ }
167
+
168
+ module.exports = InitCommand;
@@ -122,7 +122,7 @@ describe('source:get command tests', () => {
122
122
  const version = '1.1.1';
123
123
  await GetCommand.run([`-s=${name}@${version}`]).catch(err => {
124
124
  expect(err.message).toContain(
125
- chalk.red(`The version \"1.1.1\" for source name \"test-01\" doesn't exist.`),
125
+ chalk.red(`The version "1.1.1" for source name "test-01" doesn't exist.`),
126
126
  );
127
127
  });
128
128
  });
@@ -104,9 +104,9 @@ describe('source:install command tests', () => {
104
104
  });
105
105
  test('Check executing with invalid file parameter', async () => {
106
106
  await InstallCommand.run(['test-03', '-f=notexist.json']).catch(err => {
107
- expect(err.message).toEqual(
107
+ expect(err.message).toContain(
108
108
  `Something went wrong trying to read the variables file.` +
109
- `\nENOENT: no such file or directory, open 'notexist.json'`,
109
+ `\nENOENT: no such file or directory`,
110
110
  );
111
111
  });
112
112
  });
@@ -10,15 +10,19 @@ governing permissions and limitations under the License.
10
10
  */
11
11
 
12
12
  const { Command } = require('@oclif/command');
13
- const { readFile } = require('fs/promises');
14
13
 
15
14
  const logger = require('../../classes/logger');
16
- const { initSdk, initRequestId, promptConfirm } = require('../../helpers');
17
- const { ignoreCacheFlag, autoConfirmActionFlag, envFileFlag } = require('../../utils');
15
+ const { initSdk, initRequestId, promptConfirm, importFiles } = require('../../helpers');
16
+ const {
17
+ ignoreCacheFlag,
18
+ autoConfirmActionFlag,
19
+ envFileFlag,
20
+ checkPlaceholders,
21
+ readFileContents,
22
+ validateAndInterpolateMesh,
23
+ getFilesInMeshConfig,
24
+ } = require('../../utils');
18
25
  const { getMeshId, updateMesh } = require('../../lib/devConsole');
19
- const meshInterpolation = require('../../meshInterpolation');
20
-
21
- const dotenv = require('dotenv');
22
26
 
23
27
  class UpdateCommand extends Command {
24
28
  static args = [{ name: 'file' }];
@@ -43,27 +47,16 @@ class UpdateCommand extends Command {
43
47
 
44
48
  const ignoreCache = await flags.ignoreCache;
45
49
  const autoConfirmAction = await flags.autoConfirmAction;
46
- const envFilePath=await flags.env;
50
+ const envFilePath = await flags.env;
47
51
 
48
52
  const { imsOrgId, projectId, workspaceId } = await initSdk({
49
53
  ignoreCache,
50
54
  });
51
55
 
52
- let inputMeshData;
53
-
54
56
  //Input the mesh data from the input file
55
- try {
56
- inputMeshData = await readFile(args.file, 'utf8');
57
- } catch (error) {
58
- logger.error(error);
59
-
60
- this.log(error.message);
61
- this.error(
62
- 'Unable to read the mesh configuration file provided. Please check the file and try again.',
63
- );
64
- }
57
+ let inputMeshData = await readFileContents(args.file, this, 'mesh');
65
58
 
66
- let meshId;
59
+ let meshId = null;
67
60
 
68
61
  try {
69
62
  meshId = await getMeshId(imsOrgId, projectId, workspaceId);
@@ -75,61 +68,36 @@ class UpdateCommand extends Command {
75
68
 
76
69
  let data;
77
70
 
78
- if (envFilePath) {
79
- let envFileContent;
80
-
81
- //Read the environment file
71
+ if (checkPlaceholders(inputMeshData)) {
72
+ this.log('The provided mesh contains placeholders. Starting mesh interpolation process.');
73
+ data = await validateAndInterpolateMesh(inputMeshData, envFilePath, this);
74
+ } else {
82
75
  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.');
76
+ data = JSON.parse(inputMeshData);
77
+ } catch (err) {
78
+ this.log(err.message);
79
+ this.error('Input mesh file is not a valid JSON. Please check the file provided.');
87
80
  }
81
+ }
88
82
 
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
- });
83
+ let filesList = [];
108
84
 
109
- if (interpolationStatus == 'failed') {
110
- this.error(
111
- 'The mesh file cannot be interpolated due to missing keys : ' + missingKeys.toString(),
112
- );
113
- }
85
+ try {
86
+ filesList = getFilesInMeshConfig(data, args.file);
87
+ } catch (err) {
88
+ this.log(err.message);
89
+ this.error('Input mesh config is not valid.');
90
+ }
114
91
 
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 {
92
+ // if local files are present, import them in files array in meshConfig
93
+ if (filesList.length) {
128
94
  try {
129
- data = JSON.parse(inputMeshData);
95
+ data = await importFiles(data, filesList, args.file, flags.autoConfirmAction);
130
96
  } catch (err) {
131
97
  this.log(err.message);
132
- this.error('Input mesh file is not a valid JSON. Please check the input file provided.');
98
+ this.error(
99
+ 'Unable to import the files in the mesh config. Please check the file and try again.',
100
+ );
133
101
  }
134
102
  }
135
103