generator-begcode
Version:
Spring Boot + Angular/React/Vue in one handy generator
317 lines (316 loc) • 12.7 kB
JavaScript
import chalk from 'chalk';
import { readFileSync, readdirSync, statSync } from 'node:fs';
import { join } from 'node:path';
import { loadConfigs } from './docker-base.js';
import { applicationTypes, monitoringTypes, serviceDiscoveryTypes } from '../../../jdl/jhipster/index.js';
import { convertSecretToBase64 } from '../../base/support/index.js';
const { MICROSERVICE, MONOLITH, GATEWAY } = applicationTypes;
const { PROMETHEUS } = monitoringTypes;
const monitoring = monitoringTypes;
const NO_MONITORING = monitoring.NO;
const { CONSUL, EUREKA, NO: NO_SERVICE_DISCOVERY } = serviceDiscoveryTypes;
export default {
askForApplicationType,
askForGatewayType,
askForPath,
askForApps,
askForClustersMode,
askForMonitoring,
askForServiceDiscovery,
askForAdminPassword,
askForDockerRepositoryName,
askForDockerPushCommand,
loadConfigs,
};
async function askForApplicationType() {
if (!this.options.askAnswered && (this.regenerate || this.config.existed))
return;
const prompts = [
{
type: 'list',
name: 'deploymentApplicationType',
message: 'Which *type* of application would you like to deploy?',
choices: [
{
value: MONOLITH,
name: 'Monolithic application',
},
{
value: MICROSERVICE,
name: 'Microservice application',
},
],
default: MONOLITH,
},
];
const props = await this.prompt(prompts, this.config);
this.deploymentApplicationType = props.deploymentApplicationType;
}
async function askForGatewayType() {
if (!this.options.askAnswered && (this.regenerate || this.config.existed))
return;
if (this.deploymentApplicationType !== MICROSERVICE)
return;
const prompts = [
{
type: 'list',
name: 'gatewayType',
message: 'Which *type* of gateway would you like to use?',
choices: [
{
value: 'SpringCloudGateway',
name: 'JHipster gateway based on Spring Cloud Gateway',
},
],
default: 'SpringCloudGateway',
},
];
const props = await this.prompt(prompts, this.config);
this.gatewayType = props.gatewayType;
}
async function askForPath() {
if (!this.options.askAnswered && (this.regenerate || this.config.existed))
return;
const deploymentApplicationType = this.deploymentApplicationType;
let messageAskForPath;
if (deploymentApplicationType === MONOLITH) {
messageAskForPath = 'Enter the root directory where your applications are located';
}
else {
messageAskForPath = 'Enter the root directory where your gateway(s) and microservices are located';
}
const prompts = [
{
type: 'input',
name: 'directoryPath',
message: messageAskForPath,
default: this.directoryPath || '../',
validate: async (input) => {
const path = this.destinationPath(input);
try {
if (statSync(path).isDirectory) {
const appsFolders = getAppFolders.call(this, path, deploymentApplicationType);
if (appsFolders.length === 0) {
return deploymentApplicationType === MONOLITH
? `No monolith found in ${path}`
: `No microservice or gateway found in ${path}`;
}
return true;
}
}
catch {
}
return `${path} is not a directory or doesn't exist`;
},
},
];
const props = await this.prompt(prompts, this.config);
this.directoryPath = props.directoryPath;
if (!this.directoryPath.endsWith('/')) {
this.log.log(chalk.yellow(`The path "${this.directoryPath}" does not end with a trailing "/", adding it anyway.`));
this.directoryPath += '/';
}
this.appsFolders = getAppFolders.call(this, this.destinationPath(this.directoryPath), deploymentApplicationType);
for (let i = this.appsFolders.length - 1; i >= 0; i--) {
if (this.appsFolders[i] === 'jhipster-registry' || this.appsFolders[i] === 'registry') {
this.appsFolders.splice(i, 1);
}
}
this.log.log(chalk.green(`${this.appsFolders.length} applications found at ${this.destinationPath(this.directoryPath)}\n`));
}
async function askForApps() {
if (!this.options.askAnswered && (this.regenerate || this.config.existed))
return;
const messageAskForApps = 'Which applications do you want to include in your configuration?';
const prompts = [
{
type: 'checkbox',
name: 'chosenApps',
message: messageAskForApps,
choices: this.appsFolders ?? [],
default: this.jhipsterConfig.appsFolders,
validate: input => (input.length === 0 ? 'Please choose at least one application' : true),
},
];
const props = await this.prompt(prompts);
this.appsFolders = this.jhipsterConfig.appsFolders = props.chosenApps;
loadConfigs.call(this);
}
async function askForClustersMode() {
if (!this.options.askAnswered && (this.regenerate || this.config.existed))
return;
const clusteredDbApps = [];
this.appConfigs.forEach((appConfig, index) => {
if (appConfig.databaseTypeMongodb || appConfig.databaseTypeCouchbase) {
clusteredDbApps.push(this.appsFolders[index]);
}
});
if (clusteredDbApps.length === 0)
return;
const prompts = [
{
type: 'checkbox',
name: 'clusteredDbApps',
message: 'Which applications do you want to use with clustered databases (only available with MongoDB and Couchbase)?',
choices: clusteredDbApps,
default: this.clusteredDbApps,
},
];
const props = await this.prompt(prompts, this.config);
this.clusteredDbApps = props.clusteredDbApps;
}
async function askForMonitoring() {
if (!this.options.askAnswered && (this.regenerate || this.config.existed))
return;
const prompts = [
{
type: 'list',
name: 'monitoring',
message: 'Do you want to setup monitoring for your applications ?',
choices: [
{
value: NO_MONITORING,
name: 'No',
},
{
value: PROMETHEUS,
name: 'Yes, for metrics only with Prometheus',
},
],
default: this.monitoring ? this.monitoring : NO_MONITORING,
},
];
const props = await this.prompt(prompts, this.config);
this.monitoring = props.monitoring;
}
async function askForServiceDiscovery() {
if (!this.options.askAnswered && (this.regenerate || this.config.existed))
return;
const serviceDiscoveryEnabledApps = [];
this.appConfigs.forEach(appConfig => {
if (appConfig.serviceDiscoveryAny) {
serviceDiscoveryEnabledApps.push({
baseName: appConfig.baseName,
serviceDiscoveryType: appConfig.serviceDiscoveryType,
});
}
});
if (serviceDiscoveryEnabledApps.length === 0) {
this.serviceDiscoveryType = this.jhipsterConfig.serviceDiscoveryType = NO_SERVICE_DISCOVERY;
return;
}
if (serviceDiscoveryEnabledApps.every(app => app.serviceDiscoveryType === CONSUL)) {
this.serviceDiscoveryType = this.jhipsterConfig.serviceDiscoveryType = CONSUL;
this.log.log(chalk.green('Consul detected as the service discovery and configuration provider used by your apps'));
}
else if (serviceDiscoveryEnabledApps.every(app => app.serviceDiscoveryType === EUREKA)) {
this.serviceDiscoveryType = this.jhipsterConfig.serviceDiscoveryType = EUREKA;
this.log.log(chalk.green('JHipster registry detected as the service discovery and configuration provider used by your apps'));
}
else {
this.log.warn(chalk.yellow('Unable to determine the service discovery and configuration provider to use from your apps configuration.'));
this.log.verboseInfo('Your service discovery enabled apps:');
serviceDiscoveryEnabledApps.forEach(app => {
this.log.verboseInfo(` -${app.baseName} (${app.serviceDiscoveryType})`);
});
const prompts = [
{
type: 'list',
name: 'serviceDiscoveryType',
message: 'Which Service Discovery registry and Configuration server would you like to use ?',
choices: [
{
value: CONSUL,
name: 'Consul',
},
{
value: EUREKA,
name: 'JHipster Registry',
},
{
value: NO_SERVICE_DISCOVERY,
name: 'No Service Discovery and Configuration',
},
],
default: CONSUL,
},
];
const props = await this.prompt(prompts, this.config);
this.serviceDiscoveryType = props.serviceDiscoveryType;
}
}
async function askForAdminPassword() {
if (!this.options.askAnswered && (this.regenerate || this.config.existed))
return;
if (this.serviceDiscoveryType !== EUREKA)
return;
const prompts = [
{
type: 'input',
name: 'adminPassword',
message: 'Enter the admin password used to secure the JHipster Registry',
default: 'admin',
validate: input => (input.length < 5 ? 'The password must have at least 5 characters' : true),
},
];
const props = await this.prompt(prompts, this.config);
this.adminPassword = props.adminPassword;
this.adminPasswordBase64 = convertSecretToBase64(this.adminPassword);
}
async function askForDockerRepositoryName() {
if (!this.options.askAnswered && (this.regenerate || this.config.existed))
return;
const prompts = [
{
type: 'input',
name: 'dockerRepositoryName',
message: 'What should we use for the base Docker repository name?',
default: this.dockerRepositoryName,
},
];
const props = await this.prompt(prompts, this.config);
this.dockerRepositoryName = props.dockerRepositoryName;
}
async function askForDockerPushCommand() {
if (!this.options.askAnswered && (this.regenerate || this.config.existed))
return;
const prompts = [
{
type: 'input',
name: 'dockerPushCommand',
message: 'What command should we use for push Docker image to repository?',
default: this.dockerPushCommand ? this.dockerPushCommand : 'docker push',
},
];
const props = await this.prompt(prompts, this.config);
this.dockerPushCommand = props.dockerPushCommand;
}
export function getAppFolders(directory, deploymentApplicationType) {
const files = readdirSync(directory);
const appsFolders = [];
files.forEach(file => {
try {
if (statSync(join(directory, file)).isDirectory()) {
const yoRcFile = join(directory, file, '.yo-rc.json');
if (statSync(yoRcFile).isFile()) {
try {
const fileData = JSON.parse(readFileSync(yoRcFile).toString());
if (fileData['generator-begcode'].baseName !== undefined &&
(deploymentApplicationType === undefined ||
deploymentApplicationType === (fileData['generator-begcode'].applicationType ?? MONOLITH) ||
(deploymentApplicationType === MICROSERVICE && fileData['generator-begcode'].applicationType === GATEWAY))) {
appsFolders.push(file.match(/([^/]*)\/*$/)[1]);
}
}
catch (err) {
this.log.error(chalk.red(`${yoRcFile}: this .yo-rc.json can't be read`));
this.log.debug('Error:', err);
}
}
}
}
catch {
}
});
return appsFolders;
}