UNPKG

generator-begcode

Version:

Spring Boot + Angular/React/Vue in one handy generator

251 lines (250 loc) 13.6 kB
import { intersection } from 'lodash-es'; import BaseApplicationGenerator from '../base-application/index.js'; import { createDockerComposeFile, createDockerExtendedServices } from '../docker/support/index.js'; import { createFaker, stringHashCode } from '../base/support/index.js'; import { getJdbcUrl, getR2dbcUrl } from '../spring-data-relational/support/index.js'; import { dockerFiles } from './files.js'; import { SERVICE_COMPLETED_SUCCESSFULLY, SERVICE_HEALTHY } from './constants.js'; export default class DockerGenerator extends BaseApplicationGenerator { hasServicesFile = false; async beforeQueue() { if (!this.fromBlueprint) { await this.composeWithBlueprints(); } if (!this.delegateToBlueprint) { await this.dependsOnBootstrapApplicationServer(); } } get loading() { return this.asLoadingTaskGroup({ loading({ applicationDefaults }) { applicationDefaults({ dockerServices: [], }); }, }); } get [BaseApplicationGenerator.LOADING]() { return this.delegateTasksToBlueprint(() => this.loading); } get preparing() { return this.asPreparingTaskGroup({ dockerServices({ application }) { const dockerServices = application.dockerServices; if (application.authenticationTypeOauth2) { dockerServices.push('keycloak'); } if (application.searchEngineElasticsearch) { dockerServices.push('elasticsearch'); } if (application.messageBrokerKafka || application.messageBrokerPulsar) { dockerServices.push(application.messageBroker); } if (application.serviceDiscoveryConsul || application.serviceDiscoveryEureka || application.serviceDiscoveryNacos) { dockerServices.push(application.serviceDiscoveryType); } if (application.serviceDiscoveryAny || application.applicationTypeGateway || application.applicationTypeMicroservice) { dockerServices.push('zipkin'); } if (application.enableSwaggerCodegen) { dockerServices.push('swagger-editor'); } if (application.cacheProviderMemcached || application.cacheProviderRedis || application.cacheProviderHazelcast) { dockerServices.push(application.cacheProvider); } if (application.databaseTypeCassandra || application.databaseTypeCouchbase || application.databaseTypeMongodb || application.databaseTypeNeo4j) { dockerServices.push(application.databaseType); } if (application.prodDatabaseTypePostgresql || application.prodDatabaseTypeMariadb || application.prodDatabaseTypeMysql || application.prodDatabaseTypeMssql) { dockerServices.push(application.prodDatabaseType); } }, addAppServices({ application, source }) { const writeInitialServicesFile = () => { if (!this.hasServicesFile) { const dockerFile = createDockerComposeFile(application.lowercaseBaseName); this.writeDestination(`${application.dockerServicesDir}services.yml`, dockerFile); } this.hasServicesFile = true; }; source.addDockerExtendedServiceToApplicationAndServices = (...services) => { const extendedServices = createDockerExtendedServices(...services); writeInitialServicesFile(); this.mergeDestinationYaml(`${application.dockerServicesDir}services.yml`, extendedServices); this.mergeDestinationYaml(`${application.dockerServicesDir}app.yml`, extendedServices); }; source.addDockerExtendedServiceToServices = (...services) => { const extendedServices = createDockerExtendedServices(...services); writeInitialServicesFile(); this.mergeDestinationYaml(`${application.dockerServicesDir}services.yml`, extendedServices); }; source.addDockerExtendedServiceToApplication = (...services) => { const extendedServices = createDockerExtendedServices(...services); this.mergeDestinationYaml(`${application.dockerServicesDir}app.yml`, extendedServices); }; source.addDockerDependencyToApplication = (...services) => { this.mergeDestinationYaml(`${application.dockerServicesDir}app.yml`, { services: { app: { depends_on: Object.fromEntries(services.map(({ serviceName, condition }) => [ serviceName, { condition, }, ])), }, }, }); }; }, }); } get [BaseApplicationGenerator.PREPARING]() { return this.preparing; } get writing() { return this.asWritingTaskGroup({ async writeDockerFiles({ application }) { if (application.authenticationTypeOauth2) { const faker = await createFaker(); faker.seed(stringHashCode(application.baseName)); application.keycloakSecrets = Array.from(Array(6), () => faker.string.uuid()); } await this.writeFiles({ sections: dockerFiles, context: application, }); }, }); } get [BaseApplicationGenerator.WRITING]() { return this.writing; } get postWriting() { return this.asPostWritingTaskGroup({ async dockerServices({ application, source }) { if (application.dockerServices.includes('cassandra')) { const serviceName = application.databaseType; source.addDockerExtendedServiceToApplicationAndServices({ serviceName }, { serviceFile: './cassandra.yml', serviceName: 'cassandra-migration' }); source.addDockerDependencyToApplication({ serviceName, condition: SERVICE_HEALTHY }, { serviceName: 'cassandra-migration', condition: SERVICE_COMPLETED_SUCCESSFULLY }); } for (const serviceName of intersection(['postgresql', 'mysql', 'mariadb', 'mssql'], application.dockerServices)) { const profiles = application.prodDatabaseType === application.devDatabaseType ? undefined : ['', 'prod']; source.addDockerExtendedServiceToApplication({ serviceName }); source.addDockerExtendedServiceToServices({ serviceName, additionalConfig: { profiles } }); source.addDockerDependencyToApplication({ serviceName, condition: SERVICE_HEALTHY }); } for (const serviceName of intersection(['couchbase', 'mongodb', 'neo4j', 'elasticsearch', 'keycloak'], application.dockerServices)) { source.addDockerExtendedServiceToApplicationAndServices({ serviceName }); source.addDockerDependencyToApplication({ serviceName, condition: SERVICE_HEALTHY }); } for (const serviceName of application.dockerServices.filter(service => ['redis', 'memcached', 'pulsar'].includes(service))) { source.addDockerExtendedServiceToApplicationAndServices({ serviceName }); } if (application.dockerServices.includes('eureka')) { const depends_on = application.authenticationTypeOauth2 ? { keycloak: { condition: SERVICE_HEALTHY, }, } : undefined; source.addDockerExtendedServiceToApplicationAndServices({ serviceName: 'jhipster-registry', additionalConfig: { depends_on, }, }); source.addDockerDependencyToApplication({ serviceName: 'jhipster-registry', condition: SERVICE_HEALTHY }); } if (application.dockerServices.includes('consul')) { source.addDockerExtendedServiceToApplicationAndServices({ serviceName: 'consul' }, { serviceFile: './consul.yml', serviceName: 'consul-config-loader' }); } if (application.dockerServices.includes('kafka')) { source.addDockerExtendedServiceToApplicationAndServices({ serviceName: 'kafka' }); } }, packageJsonScripts({ application }) { const scriptsStorage = this.packageJson.createStorage('scripts'); const { databaseType, databaseTypeSql, prodDatabaseType, prodDatabaseTypeNo, prodDatabaseTypeOracle } = application; let postServicesSleep; if (databaseTypeSql) { if (prodDatabaseTypeNo || prodDatabaseTypeOracle) { scriptsStorage.set('docker:db:up', `echo "Docker for db ${prodDatabaseType} not configured for application ${application.baseName}"`); } else { const dockerFile = `${application.dockerServicesDir}${prodDatabaseType}.yml`; scriptsStorage.set({ 'docker:db:up': `docker compose -f ${dockerFile} up --wait`, 'docker:db:down': `docker compose -f ${dockerFile} down -v`, }); } } else { const dockerFile = `${application.dockerServicesDir}${databaseType}.yml`; if (this.fs.exists(this.destinationPath(dockerFile))) { scriptsStorage.set({ 'docker:db:up': `docker compose -f ${dockerFile} up --wait`, 'docker:db:down': `docker compose -f ${dockerFile} down -v`, }); if (application.databaseTypeCassandra) { postServicesSleep = 10; } } else { scriptsStorage.set('docker:db:up', `echo "Docker for db ${databaseType} not configured for application ${application.baseName}"`); } } ['keycloak', 'elasticsearch', 'kafka', 'consul', 'redis', 'memcached', 'jhipster-registry'].forEach(dockerConfig => { const dockerFile = `${application.dockerServicesDir}${dockerConfig}.yml`; if (this.fs.exists(this.destinationPath(dockerFile))) { scriptsStorage.set(`docker:${dockerConfig}:up`, `docker compose -f ${dockerFile} up --wait`); scriptsStorage.set(`docker:${dockerConfig}:down`, `docker compose -f ${dockerFile} down -v`); } }); if (postServicesSleep) { scriptsStorage.set({ 'postservices:up': `sleep ${postServicesSleep}`, }); } if (this.hasServicesFile) { scriptsStorage.set({ 'services:up': `docker compose -f ${application.dockerServicesDir}services.yml up --wait`, 'ci:e2e:teardown:docker': `docker compose -f ${application.dockerServicesDir}services.yml down -v && docker ps -a`, }); } scriptsStorage.set({ 'app:up': `docker compose -f ${application.dockerServicesDir}app.yml up --wait`, 'ci:e2e:prepare:docker': 'npm run services:up --if-present && docker ps -a', 'ci:e2e:prepare': 'npm run ci:e2e:prepare:docker', 'ci:e2e:teardown': 'npm run ci:e2e:teardown:docker --if-present', }); }, }); } get [BaseApplicationGenerator.POST_WRITING]() { return this.asPostWritingTaskGroup(this.delegateToBlueprint ? {} : this.postWriting); } get end() { return this.asEndTaskGroup({ async dockerComposeUp({ control }) { if (!control.enviromentHasDockerCompose) { this.log(''); this.log.warn('Docker Compose V2 is not installed on your computer. Some features may not work as expected. Read https://docs.docker.com/compose/install/'); } }, }); } getJDBCUrl(databaseType, options = {}) { return getJdbcUrl(databaseType, options); } getR2DBCUrl(databaseType, options = {}) { return getR2dbcUrl(databaseType, options); } }