Skip to content

Commit cd8bbec

Browse files
authored
Merge pull request #148 from microservices-suite/repo-engineering/universal-cli
refactor: change logic to merge layer of security
2 parents f001fd1 + 5e05345 commit cd8bbec

File tree

4 files changed

+104
-67
lines changed

4 files changed

+104
-67
lines changed

.suite-cli/cli/cli.js

Lines changed: 73 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const { Command } = require('commander');
55
const { createPromptModule } = require('inquirer');
66
const { execSync } = require('node:child_process')
77
const actionHandlers = require('./scripts')
8-
const { logInfo, getExistingServices, getExistingApps, getNextAvailablePort, scaffoldApp, scaffoldGateways } = require('./scripts/scripts.module');
8+
const { logInfo, getExistingComponent, getExistingApps, getNextAvailablePort, scaffoldApp, scaffoldGateways } = require('./scripts/scripts.module');
99
const { cwd } = require('node:process');
1010
const program = new Command()
1111
const prompt = createPromptModule()
@@ -123,6 +123,7 @@ program
123123
}
124124
])
125125
.then(answers => {
126+
const existing_services = getExistingComponent({ key: 'services', currentDir: cwd() })
126127
switch (answers.resource) {
127128
case 'monorepo':
128129
// Additional prompts specific to 'monorepo' resource
@@ -185,28 +186,38 @@ program
185186
});
186187
break;
187188
case 'service':
188-
const existing_services = getExistingServices({ currentDir: cwd() })
189189
prompt([
190190
{
191191
type: 'input',
192192
name: 'service_name',
193193
message: 'Enter service name:',
194194
// TODO: validate workspace compliant name using regex
195195
validate: input => input ? true : 'Name cannot be empty',
196-
}, {
197-
type: 'input',
198-
name: 'port',
199-
message: 'Enter port (optional):',
200-
default: getNextAvailablePort({ services: existing_services }),
201-
validate: input => input === '' || !isNaN(input) ? true : 'Port must be a number.'
202-
}
203-
]).then((answers) => actionHandlers.scaffoldNewService({
204-
answers: {
205-
...answers,
206-
private: true,
207-
port: parseFloat(answers.port)
208-
}
209-
}))
196+
},
197+
]).then((ans) => {
198+
const { service_name } = ans;
199+
const service_idx = existing_services.findIndex((s) => s.name === service_name);
200+
// if service exists return the port otherwise generate next available port
201+
const next_port = existing_services[service_idx]?.port || getNextAvailablePort({ key: existing_services, port: 'port' });
202+
prompt([
203+
{
204+
type: 'input',
205+
name: 'port',
206+
message: 'Enter port (optional):',
207+
default: next_port,
208+
validate: input => input === '' || !isNaN(input) ? true : 'Port must be a number.'
209+
}
210+
]).then((answers) => {
211+
actionHandlers.scaffoldNewService({
212+
answers: {
213+
...answers,
214+
service_name,
215+
private: true,
216+
port: parseFloat(answers.port)
217+
}
218+
})
219+
});
220+
});
210221
break;
211222
case 'library':
212223
prompt([
@@ -220,9 +231,8 @@ program
220231
]).then((answers) => actionHandlers.scaffoldNewLibrary({ answers: { ...answers, private: false } }))
221232
break
222233
case 'app':
223-
const all_services = getExistingServices({ currentDir: cwd() })
234+
const existing_apps = getExistingComponent({ key: 'apps', currentDir: cwd() })
224235
const formatServiceName = (service) => `${service.name}: ${service.port}`;
225-
226236
prompt([
227237
{
228238
type: 'input',
@@ -233,42 +243,55 @@ program
233243
type: 'checkbox',
234244
name: 'services',
235245
message: 'Select services',
236-
choices: all_services.map(service => ({
246+
choices: existing_services.map(service => ({
237247
name: formatServiceName(service),
238248
value: service,
239249
checked: true, // Default all services to be selected
240250
})),
241-
},
242-
{
243-
type: 'input',
244-
name: 'gateway_port',
245-
message: 'Enter port (optional):',
246-
default: 8080,
247-
validate: input => !isNaN(input) ? true : 'Port must be a number.'
248-
},
249-
{
250-
type: 'input',
251-
name: 'api_version',
252-
message: 'Whats the api version? (optional):',
253-
default: 'v1',
254-
},
255-
{
256-
type: 'input',
257-
name: 'gateway_cache_period',
258-
message: 'How long do you want the gateway to cache data (optional):',
259-
default: 3600,
260-
validate: input => !isNaN(input) ? true : 'Caching period must be a number.'
261-
},
262-
{
263-
type: 'input',
264-
name: 'gateway_timeout',
265-
message: 'How long should a request take before timing out (optional):',
266-
default: 300,
267-
validate: input => input === '' || !isNaN(input) ? true : 'Timeout must be a number.'
268-
}
269-
]).then(answers => {
270-
scaffoldApp({ answers })
271-
})
251+
}]).then((ans) => {
252+
const { app_name } = ans;
253+
const app_idx = existing_apps.findIndex((a) => a.name === app_name);
254+
// if app exists return the port otherwise generate next available port
255+
const next_port = existing_apps[app_idx]?.GATEWAY_PORT || getNextAvailablePort({ key: existing_apps, port: 'GATEWAY_PORT' });
256+
prompt([
257+
{
258+
type: 'input',
259+
name: 'gateway_port',
260+
message: 'Enter gateway port (optional):',
261+
default: next_port,
262+
validate: input => !isNaN(input) ? true : 'Port must be a number.'
263+
},
264+
{
265+
type: 'input',
266+
name: 'api_version',
267+
message: 'Whats the api version? (optional):',
268+
default: 'v1',
269+
},
270+
{
271+
type: 'input',
272+
name: 'gateway_cache_period',
273+
message: 'How long do you want the gateway to cache data (optional):',
274+
default: 3600,
275+
validate: input => !isNaN(input) ? true : 'Caching period must be a number.'
276+
},
277+
{
278+
type: 'input',
279+
name: 'gateway_timeout',
280+
message: 'How long should a request take before timing out (optional):',
281+
default: 300,
282+
validate: input => input === '' || !isNaN(input) ? true : 'Timeout must be a number.'
283+
}
284+
]).then((answers) => {
285+
scaffoldApp({
286+
answers: {
287+
...answers,
288+
...ans,
289+
port: parseFloat(answers.gateway_port)
290+
291+
}
292+
})
293+
});
294+
})
272295
break;
273296
case 'gateway':
274297
const all_apps = getExistingApps({ currentDir: cwd() });

.suite-cli/cli/scripts/assets/ecosystemContent.asset.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module.exports = ({ answers }) => `
22
module.exports = {
33
apps : [{
4-
name : ${answers.service_name},
4+
name : "${answers.service_name}",
55
autorestart: true,
66
watch: true,
77
time: true,
@@ -10,14 +10,14 @@ module.exports = {
1010
env_production: {
1111
NODE_ENV: "prod",
1212
DATABASE_URL:"mongodb://mongodb:27017/${answers.project_base.slice(1)}_${answers.service_name}_proddb",
13-
EXCHANGE:${answers.project_base},
13+
EXCHANGE:"${answers.project_base}",
1414
AMQP_HOST:"amqp://rabbitmq:5672",
1515
PORT:${answers.port}
1616
},
1717
env_development: {
1818
NODE_ENV: "dev",
1919
DATABASE_URL:"mongodb://mongodb:27017/${answers.project_base.slice(1)}_${answers.service_name}_devdb",
20-
EXCHANGE:${answers.project_base},
20+
EXCHANGE:"${answers.project_base}",
2121
AMQP_HOST:"amqp://rabbitmq:5672",
2222
PORT:${answers.port}
2323
}

.suite-cli/cli/scripts/commands/scaffoldNewService.cmd.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ const { scaffoldNewService, logError } = require('../scripts.module')
33

44
module.exports = async ({ answers }) => {
55
try {
6+
console.log({answers})
7+
68
await scaffoldNewService({ answers });
79
} catch (error) {
810
logError({ error })

.suite-cli/cli/scripts/scripts.module.js

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,16 +1350,17 @@ const addProjectConfigs = ({ project_root, answers }) => {
13501350
}
13511351

13521352
// Function to get the next available port
1353-
const getNextAvailablePort = ({ services }) => {
1354-
const usedPorts = services.map(service => service.port).sort((a, b) => a - b);
1355-
let last_port = usedPorts[usedPorts.length - 1] || 9000
1353+
const getNextAvailablePort = ({ key, port }) => {
1354+
const used_ports = key.map(k => k[port]).sort((a, b) => a - b);
1355+
let last_port = used_ports[used_ports.length - 1] || 9000
13561356
return last_port + 1;
13571357
};
13581358

1359-
const getExistingServices = ({ currentDir }) => {
1360-
const { services } = readFileContent({ currentDir })
1361-
return services
1362-
}
1359+
const getExistingComponent = ({ key, currentDir }) => {
1360+
const fileContent = readFileContent({ currentDir });
1361+
// Access the dynamic key from fileContent
1362+
return fileContent[key]; // Dynamically access the key in the object
1363+
};
13631364

13641365
const getExistingApps = ({ currentDir }) => {
13651366
const { apps } = readFileContent({ currentDir });
@@ -1373,22 +1374,34 @@ const registerServiceWithSuiteJson = ({ root_dir, name, port }) => {
13731374
if (!config.services) {
13741375
config.services = [];
13751376
}
1376-
config.services.push({ name, port });
1377+
const idx = config.services.findIndex((s) => s.name === name);
1378+
if (idx !== -1) {
1379+
config.services[idx] = { name, port }
1380+
}
1381+
else {
1382+
config.services.push({ name, port });
1383+
}
13771384

13781385
// keep the services ordered by port
13791386
config.services.sort((a, b) => a.port - b.port);
13801387
writeFile(configPath, JSON.stringify(config, null, 2), 'utf8');
13811388
}
13821389

1383-
const registerAppWithSuiteJson = ({ root_dir, name, services }) => {
1390+
const registerAppWithSuiteJson = ({ root_dir, name, services, port }) => {
13841391
// Read the project configuration file
13851392
const configPath = resolve(root_dir, 'suite.json');
13861393
const config = JSON.parse(readFileSync(configPath, 'utf8'));
13871394
const services_names = services.map((s) => s.name);
13881395
if (!config.apps) {
13891396
config.apps = [];
13901397
}
1391-
config.apps.push({ name, services: services_names });
1398+
const idx = config.apps.findIndex((a) => a.name === name);
1399+
if (idx !== -1) {
1400+
config.apps[idx] = { name, GATEWAY_PORT: port, services: services_names }
1401+
}
1402+
else {
1403+
config.apps.push({ name, GATEWAY_PORT: port, services: services_names });
1404+
}
13921405

13931406
// keep the apps ordered by names
13941407
config.apps.sort((a, b) => a.name - b.name);
@@ -1423,7 +1436,6 @@ const test = async ({ package }) => {
14231436
}
14241437

14251438
const scaffoldApp = ({ answers }) => {
1426-
14271439
const { webserver } = readFileContent({ currentDir: cwd() });
14281440
const { projectName } = readFileContent({ currentDir: cwd() });
14291441
const project_root = generatRootPath({ currentDir: cwd() });
@@ -1470,7 +1482,7 @@ const scaffoldApp = ({ answers }) => {
14701482
gateway_cache_period: answers.gateway_cache_period,
14711483
gateway_timeout: answers.gateway_timeout
14721484
});
1473-
registerAppWithSuiteJson({ root_dir: project_root, name: answers.app_name, services: answers.services })
1485+
registerAppWithSuiteJson({ root_dir: project_root, name: answers.app_name, services: answers.services, port: answers.port })
14741486

14751487
}
14761488
const readFileContent = ({ currentDir }) => {
@@ -1631,7 +1643,7 @@ const scaffoldGateways = async ({ answers }) => {
16311643
const { projectName } = readFileContent({ currentDir: cwd() });
16321644
let { apps } = answers;
16331645
const project_root = generatRootPath({ currentDir: cwd() });
1634-
const service_objects = getExistingServices({ currentDir: cwd() });
1646+
const service_objects = getExistingComponent({ key, currentDir: cwd() });
16351647
// add port to services in each app eg ['auth']=>[{name:'auth',port:9001}]
16361648
apps = apps.map((app) => {
16371649
app.services.map((name, i) => {
@@ -1720,7 +1732,7 @@ module.exports = {
17201732
scaffoldNewService,
17211733
scaffoldNewLibrary,
17221734
getNextAvailablePort,
1723-
getExistingServices,
1735+
getExistingComponent,
17241736
test,
17251737
scaffoldApp,
17261738
scaffoldGateways,

0 commit comments

Comments
 (0)