Skip to content

Commit 8454814

Browse files
authored
Merge pull request #128 from microservices-suite/repo-engineering/universal-cli
Repo engineering/universal cli
2 parents cf5ff2f + d724f46 commit 8454814

File tree

9 files changed

+149
-84
lines changed

9 files changed

+149
-84
lines changed

.suite-cli/cli/cli.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ const { Command } = require('commander');
55
const { createPromptModule } = require('inquirer');
66
const { execSync } = require('node:child_process')
77
const actionHandlers = require('./scripts')
8-
const { logInfo } = require('./scripts/scripts.module');
8+
const { logInfo, getExistingServices, getNextAvailablePort } = require('./scripts/scripts.module');
9+
const { cwd } = require('node:process');
910
const program = new Command()
1011
const prompt = createPromptModule()
1112
program
@@ -155,6 +156,12 @@ program
155156
name: 'service_name',
156157
message: 'Initial service:',
157158
default: 'microservice1'
159+
}, {
160+
type: 'input',
161+
name: 'port',
162+
message: 'Enter port (optional):',
163+
default: 9001,
164+
validate: input => input === '' || !isNaN(input) ? true : 'Port must be a number.'
158165
}
159166

160167
])
@@ -166,13 +173,20 @@ program
166173
});
167174
break;
168175
case 'service':
176+
const existing_services = getExistingServices({ currentDir: cwd() })
169177
prompt([
170178
{
171179
type: 'input',
172180
name: 'service_name',
173181
message: 'Enter service name:',
174182
// TODO: validate workspace compliant name using regex
175183
validate: input => input ? true : 'Name cannot be empty',
184+
}, {
185+
type: 'input',
186+
name: 'port',
187+
message: 'Enter port (optional):',
188+
default: getNextAvailablePort({ services: existing_services }),
189+
validate: input => input === '' || !isNaN(input) ? true : 'Port must be a number.'
176190
}
177191
]).then((answers) => actionHandlers.scaffoldNewService({ answers: { ...answers, private: true } }))
178192
break;

.suite-cli/cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@microservices-suite/cli",
3-
"version": "2.0.4",
3+
"version": "2.0.9",
44
"description": "This is the CLI tool for running the microservices-suite monorepo. It contains functionalities and tools required for automation and managing the repo across supported platforms. Works on Windows,MacOS and Linux as well as support to some extend other variants like SunOS, IBM AIX, FreeBSD, OpenBSD and more",
55
"main": "cli.js",
66
"repository": "https://github.com/microservices-suite/node-microservices-suite.git",

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module.exports = () => `
1+
module.exports = ({ answers }) => `
22
const { ApolloServer, gql } = require('apollo-server-express');
33
const express = require('express');
44
@@ -19,7 +19,7 @@ const server = new ApolloServer({ typeDefs, resolvers });
1919
const app = express();
2020
server.applyMiddleware({ app });
2121
22-
app.listen({ port: 4000 }, () =>
23-
console.log(\`🚀 Server ready at http://localhost:\${config.port}\${server.graphqlPath}\`)
22+
app.listen({ port: ${(answers.port + 1000) < 5000 ? 4001 : 8001} }, () =>
23+
console.log(\`🚀 Server ready at http://localhost:${(answers.port + 1000) < 5000 ? 4001 : 8001}\${server.graphqlPath}\`)
2424
);
2525
`;

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
module.exports = () => `
1+
module.exports = ({ answers }) => `
22
module.exports = {
33
apps : [{
4-
name : "upload_service",
4+
name : ${answers.service_name},
55
autorestart: true,
66
watch: true,
77
time: true,
88
script : "./index.js",
99
instances:4,
1010
env_production: {
1111
NODE_ENV: "prod",
12-
DATABASE_URL:"mongodb://mongodb:27017/supplier_service_db_dev",
13-
PORT:9001
12+
DATABASE_URL:"mongodb://mongodb:27017/${answers.service_name}",
13+
PORT:${answers.port}
1414
},
1515
env_development: {
1616
NODE_ENV: "dev",
17-
DATABASE_URL:"mongodb://mongodb:27017/supplier_service_db_dev",
18-
PORT:9001
17+
DATABASE_URL:"mongodb://mongodb:27017/${answers.service_name}",
18+
PORT:${answers.port}
1919
}
2020
}]
2121
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module.exports=()=>`
2-
PORT=9001
1+
module.exports = ({ answers }) => `
2+
PORT=${answers.port}
33
DATABASE_URL=mongodb://localhost:27017
44
`;

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

Lines changed: 66 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ const spinVanillaServices = async ({ serviceDirectories, microservicesDir, mode
451451
spinner.fail(`Service in directory ${dir} exited with code ${code}`);
452452
} else {
453453
spinner.succeed(`Service in directory ${dir} started successfully`);
454-
454+
455455
}
456456
});
457457
}));
@@ -967,9 +967,15 @@ const addPackageJson = async ({ project_root, answers }) => {
967967
}
968968
}
969969
});
970-
970+
let warningMessage
971971
childProcess.stderr.on('data', data => {
972-
spinner.text = 'Encountered an issue, check logs for more info.';
972+
const output = data.toString();
973+
974+
if (output.toLowerCase().includes('warning')) {
975+
warningMessage = output.split('\n').find(line => line.toLowerCase().includes('warning'));
976+
} else {
977+
spinner.text = 'Encountered an issue, check logs for more info.';
978+
}
973979
});
974980

975981
childProcess.on('error', error => {
@@ -981,6 +987,12 @@ const addPackageJson = async ({ project_root, answers }) => {
981987
spinner.fail('Command failed to complete successfully');
982988
return;
983989
}
990+
spinner.stop()
991+
if (warningMessage) {
992+
console.log('============================')
993+
console.warn(warningMessage)
994+
console.log('============================')
995+
}
984996
spinner.succeed('Dependencies installed successfully');
985997
spinner.info(`To start the project, run 'cd ${answers.repo_name} && suite start -v ${answers.service_name}'`)
986998
});
@@ -1069,7 +1081,7 @@ const addMicroservice = ({ project_root, answers }) => {
10691081
writeFile(join(current_dir, 'test1.js'), assets.snapshotTestContent());
10701082
break;
10711083
case `GraphQL/app1`:
1072-
writeFile(join(current_dir, 'appollo-server.js'), assets.apolloServerContent());
1084+
writeFile(join(current_dir, 'appollo-server.js'), assets.apolloServerContent({ answers }));
10731085
break;
10741086
case `k8s/${answers.service_name}`:
10751087
// TODO: move k8s into a function
@@ -1084,10 +1096,6 @@ const addMicroservice = ({ project_root, answers }) => {
10841096
});
10851097

10861098
generateMCSHelper({ project_root, answers })
1087-
writeFile(join(`${project_root}/microservices/${answers.service_name}`, 'index.js'), assets.serverContent({ answers }));
1088-
writeFile(join(`${project_root}/microservices/${answers.service_name}`, '.env'), assets.envContent());
1089-
writeFile(join(`${project_root}/microservices/${answers.service_name}`, '.env.dev'), assets.envContent());
1090-
writeFile(join(`${project_root}/microservices/${answers.service_name}`, 'ecosystem.config.js'), assets.ecosystemContent());
10911099
mkdirSync(join(project_root, '.vscode'), { recursive: true })
10921100
writeFileSync(join(project_root, '.gitignore'), assets.gitignoreContent());
10931101
writeFileSync(join(project_root, '.vscode', 'launch.json'), JSON.stringify(assets.debuggerConfigContent(), null, 2));
@@ -1203,7 +1211,7 @@ const injectService = async ({ project_root, answers, workspace_name }) => {
12031211
});
12041212

12051213
await writeFile(join(service_path, 'package.json'), JSON.stringify(packageJsonContent, null, 2));
1206-
1214+
registerServiceWithSuiteJson({ root_dir: project_root, name: answers.service_name, port: answers.port })
12071215
spinner.succeed('Service injected successfully');
12081216
} catch (error) {
12091217
spinner.fail(`Failed to inject service: ${error.message}`);
@@ -1259,6 +1267,10 @@ const generateMCSHelper = ({ project_root, answers }) => {
12591267
const indexContent = mcs === 'models' ? assets.modelIndexContent() : mcs === 'routes' ? assets.routesIndexContent() : mcs === 'controllers' ? assets.controllersIndexContent() : assets.servicesIndexContent();
12601268
writeFileSync(join(mcsPath, 'index.js'), indexContent);
12611269
});
1270+
writeFile(join(`${project_root}/microservices/${answers.service_name}`, 'index.js'), assets.serverContent({ answers }));
1271+
writeFile(join(`${project_root}/microservices/${answers.service_name}`, '.env'), assets.envContent({ answers }));
1272+
writeFile(join(`${project_root}/microservices/${answers.service_name}`, '.env.dev'), assets.envContent({ answers }));
1273+
writeFile(join(`${project_root}/microservices/${answers.service_name}`, 'ecosystem.config.js'), assets.ecosystemContent({ answers }));
12621274
}
12631275

12641276
/**
@@ -1356,11 +1368,52 @@ const scaffoldNewLibrary = async ({ answers }) => {
13561368
* @returns {void}
13571369
*/
13581370
const addProjectConfigs = ({ project_root, answers }) => {
1359-
writeFile(join(project_root, 'suite.json'), JSON.stringify(assets.suiteJSON({ answers }), null, 2));
1371+
const { service_name, port, ...suite_json } = answers
1372+
suite_json['services'] = [
1373+
{
1374+
name: service_name,
1375+
port: answers.port
1376+
}
1377+
]
1378+
answers.apis.includes('GraphQL') && (suite_json['apollo_servers'] = [{
1379+
name: 'app1',
1380+
port: (answers.port + 1000) < 5000 ? 4001 : 8001
1381+
}])
1382+
writeFile(join(project_root, 'suite.json'), JSON.stringify(assets.suiteJSON({ answers: suite_json }), null, 2));
13601383
writeFile(join(project_root, 'suite.config'), assets.suiteConfig({ answers }));
13611384
writeFile(join(project_root, '.suiterc'), assets.suiteRC({ answers }));
13621385

13631386
}
1387+
1388+
// Function to get the next available port
1389+
const getNextAvailablePort = ({ services }) => {
1390+
const usedPorts = services.map(service => service.port);
1391+
let port = 9001;
1392+
while (usedPorts.includes(port)) {
1393+
port++;
1394+
}
1395+
return port;
1396+
};
1397+
1398+
const getExistingServices = ({ currentDir }) => {
1399+
const root_dir = generatRootPath({ currentDir, height: 5 })
1400+
// Read the project configuration file
1401+
const configPath = resolve(root_dir, 'suite.json');
1402+
const config = JSON.parse(readFileSync(configPath, 'utf8'));
1403+
const existingServices = config.services || [];
1404+
return existingServices
1405+
}
1406+
const registerServiceWithSuiteJson = ({ root_dir, name, port }) => {
1407+
// Read the project configuration file
1408+
const configPath = resolve(root_dir, 'suite.json');
1409+
const config = JSON.parse(readFileSync(configPath, 'utf8'));
1410+
if (!config.services) {
1411+
config.services = [];
1412+
}
1413+
config.services.push({ name, port });
1414+
writeFile(configPath, JSON.stringify(config, null, 2), 'utf8');
1415+
}
1416+
const readFileContent = ({ path }) => { }
13641417
module.exports = {
13651418
generateDirectoryPath,
13661419
changeDirectory,
@@ -1386,5 +1439,7 @@ module.exports = {
13861439
scaffoldNewRepo,
13871440
releasePackage,
13881441
scaffoldNewService,
1389-
scaffoldNewLibrary
1442+
scaffoldNewLibrary,
1443+
getNextAvailablePort,
1444+
getExistingServices
13901445
}

gateway/apps/ecommerce-app/docker-compose.dev.yml

Lines changed: 55 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,71 +4,71 @@ services:
44
build:
55
dockerfile: DockerFile
66
context: ../../../data-persistence/mongodb
7-
rabbitmq:
8-
image: rabbitmq:3.8
9-
container_name: rabbitmq
10-
ports:
11-
- '5672:5672'
12-
- '15672:15672'
13-
healthcheck:
14-
test: ["CMD", "rabbitmq-diagnostics", "ping"]
15-
interval: 30s
16-
retries: 5
17-
restart: unless-stopped
18-
customer-service:
19-
depends_on:
20-
rabbitmq:
21-
condition: service_healthy
22-
# shared:
23-
# condition: service_healthy
24-
container_name: customer
25-
restart: always
26-
build:
27-
context: ../../../microservices/customer-service
28-
dockerfile: DockerFile.dev
29-
ports:
30-
- 9000:9000
31-
volumes:
32-
- /app/node_modules
33-
- ../../../microservices/customer-service:/app
34-
supplier-service:
35-
depends_on:
36-
rabbitmq:
37-
condition: service_healthy
38-
# shared:
39-
# condition: service_healthy
40-
container_name: supplier
41-
restart: always
42-
build:
43-
context: ../../../microservices/supplier-service
44-
dockerfile: DockerFile.dev
45-
ports:
46-
- 9001:9001
47-
volumes:
48-
- /app/node_modules
49-
- ../../../microservices/supplier-service:/app
50-
# user-service:
7+
# rabbitmq:
8+
# image: rabbitmq:3.8
9+
# container_name: rabbitmq
10+
# ports:
11+
# - '5672:5672'
12+
# - '15672:15672'
13+
# healthcheck:
14+
# test: ["CMD", "rabbitmq-diagnostics", "ping"]
15+
# interval: 30s
16+
# retries: 5
17+
# restart: unless-stopped
18+
# customer-service:
19+
# depends_on:
20+
# rabbitmq:
21+
# condition: service_healthy
22+
# # shared:
23+
# # condition: service_healthy
24+
# container_name: customer
25+
# restart: always
5126
# build:
27+
# context: ../../../microservices/customer-service
5228
# dockerfile: DockerFile.dev
53-
# context: ../../../microservices/user-service
5429
# ports:
55-
# - '9003:9003'
56-
# depends_on:
57-
# - mongodb
30+
# - 9000:9000
5831
# volumes:
5932
# - /app/node_modules
60-
# - ../../../microservices/user-service:/app
61-
# upload-service:
33+
# - ../../../microservices/customer-service:/app
34+
# supplier-service:
35+
# depends_on:
36+
# rabbitmq:
37+
# condition: service_healthy
38+
# # shared:
39+
# # condition: service_healthy
40+
# container_name: supplier
41+
# restart: always
6242
# build:
43+
# context: ../../../microservices/supplier-service
6344
# dockerfile: DockerFile.dev
64-
# context: ../../../microservices/upload-service
6545
# ports:
66-
# - '9004:9004'
67-
# depends_on:
68-
# - mongodb
46+
# - 9001:9001
6947
# volumes:
7048
# - /app/node_modules
71-
# - ../../../microservices/upload-service:/app
49+
# - ../../../microservices/supplier-service:/app
50+
user-service:
51+
build:
52+
dockerfile: DockerFile.dev
53+
context: ../../../microservices/user-service
54+
ports:
55+
- '9003:9003'
56+
depends_on:
57+
- mongodb
58+
volumes:
59+
- /app/node_modules
60+
- ../../../microservices/user-service:/app
61+
upload-service:
62+
build:
63+
dockerfile: DockerFile.dev
64+
context: ../../../microservices/upload-service
65+
ports:
66+
- '9004:9004'
67+
depends_on:
68+
- mongodb
69+
volumes:
70+
- /app/node_modules
71+
- ../../../microservices/upload-service:/app
7272
# shared:
7373
# build:
7474
# context: ./shared
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
DATABASE_URL=mongodb://mongodb:27017/user_service_db_dev
1+
DATABASE_URL=mongodb://localhost:27017/user_service_db_dev
22
PORT=9003

suite.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +0,0 @@
1-
/**
2-
* This is the main configuration file for Suite.
3-
* For full documentation, please see https://github.com/microservices-suite/node-microservices-suite
4-
*/

0 commit comments

Comments
 (0)