From 8136f5f8fdd91a1baa828013ab9767d9b9d523e0 Mon Sep 17 00:00:00 2001 From: Marcelo Shima Date: Thu, 7 Nov 2024 12:02:33 -0300 Subject: [PATCH] java: add java:server generator --- .../bootstrap-application-base/generator.ts | 3 + .../java/generators/bootstrap/generator.ts | 26 ++++ .../__snapshots__/generator.spec.ts.snap | 14 ++ generators/java/generators/server/command.ts | 26 ++++ .../java/generators/server/generator.spec.ts | 53 +++++++ .../java/generators/server/generator.ts | 130 ++++++++++++++++ generators/java/generators/server/index.ts | 20 +++ generators/server/generator.ts | 144 +----------------- generators/spring-boot/generator.ts | 14 ++ 9 files changed, 287 insertions(+), 143 deletions(-) create mode 100644 generators/java/generators/server/__snapshots__/generator.spec.ts.snap create mode 100644 generators/java/generators/server/command.ts create mode 100644 generators/java/generators/server/generator.spec.ts create mode 100644 generators/java/generators/server/generator.ts create mode 100644 generators/java/generators/server/index.ts diff --git a/generators/bootstrap-application-base/generator.ts b/generators/bootstrap-application-base/generator.ts index 7d00ff2ac619..24aa29648ef3 100644 --- a/generators/bootstrap-application-base/generator.ts +++ b/generators/bootstrap-application-base/generator.ts @@ -142,6 +142,9 @@ export default class BootstrapApplicationBase extends BaseApplicationGenerator { this.fetchFromInstalledJHipster(GENERATOR_COMMON, 'resources', 'package.json'), ); }, + loadPackageJson({ application }) { + application.jhipsterPackageJson = packageJson; + }, }); } diff --git a/generators/java/generators/bootstrap/generator.ts b/generators/java/generators/bootstrap/generator.ts index 02462d836977..11b938af13a4 100644 --- a/generators/java/generators/bootstrap/generator.ts +++ b/generators/java/generators/bootstrap/generator.ts @@ -73,6 +73,32 @@ export default class BootstrapGenerator extends BaseApplicationGenerator { return this.delegateTasksToBlueprint(() => this.configuring); } + get loading() { + return this.asLoadingTaskGroup({ + loadEnvironmentVariables({ application }) { + application.packageInfoJavadocs?.push( + { packageName: `${application.packageName}.aop.logging`, documentation: 'Logging aspect.' }, + { packageName: `${application.packageName}.management`, documentation: 'Application management.' }, + { packageName: `${application.packageName}.repository.rowmapper`, documentation: 'Webflux database column mapper.' }, + { packageName: `${application.packageName}.security`, documentation: 'Application security utilities.' }, + { packageName: `${application.packageName}.service.dto`, documentation: 'Data transfer objects for rest mapping.' }, + { packageName: `${application.packageName}.service.mapper`, documentation: 'Data transfer objects mappers.' }, + { packageName: `${application.packageName}.web.filter`, documentation: 'Request chain filters.' }, + { packageName: `${application.packageName}.web.rest.errors`, documentation: 'Rest layer error handling.' }, + { packageName: `${application.packageName}.web.rest.vm`, documentation: 'Rest layer visual models.' }, + ); + + if (application.defaultPackaging === 'war') { + this.log.info(`Using ${application.defaultPackaging} as default packaging`); + } + }, + }); + } + + get [BaseApplicationGenerator.LOADING]() { + return this.delegateTasksToBlueprint(() => this.loading); + } + get preparing() { return this.asPreparingTaskGroup({ applicationDefaults({ application }) { diff --git a/generators/java/generators/server/__snapshots__/generator.spec.ts.snap b/generators/java/generators/server/__snapshots__/generator.spec.ts.snap new file mode 100644 index 000000000000..3b1efd4c1fb0 --- /dev/null +++ b/generators/java/generators/server/__snapshots__/generator.spec.ts.snap @@ -0,0 +1,14 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`generator - java:server with defaults options should call source snapshot 1`] = `{}`; + +exports[`generator - java:server with defaults options should match files snapshot 1`] = ` +{ + ".yo-rc.json": { + "stateCleared": "modified", + }, + "package.json": { + "stateCleared": "modified", + }, +} +`; diff --git a/generators/java/generators/server/command.ts b/generators/java/generators/server/command.ts new file mode 100644 index 000000000000..de9446fa3118 --- /dev/null +++ b/generators/java/generators/server/command.ts @@ -0,0 +1,26 @@ +/** + * Copyright 2013-2024 the original author or authors from the JHipster project. + * + * This file is part of the JHipster project, see https://www.jhipster.tech/ + * for more information. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import type { JHipsterCommandDefinition } from '../../../../lib/command/types.js'; + +const command = { + configs: {}, + import: [], +} as const satisfies JHipsterCommandDefinition; + +export default command; diff --git a/generators/java/generators/server/generator.spec.ts b/generators/java/generators/server/generator.spec.ts new file mode 100644 index 000000000000..1552e18ce2ae --- /dev/null +++ b/generators/java/generators/server/generator.spec.ts @@ -0,0 +1,53 @@ +/** + * Copyright 2013-2024 the original author or authors from the JHipster project. + * + * This file is part of the JHipster project, see https://www.jhipster.tech/ + * for more information. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { basename, dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { before, describe, expect, it } from 'esmocha'; + +import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js'; +import { defaultHelpers as helpers, result } from '../../../../lib/testing/index.js'; +import Generator from './index.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const generator = `${basename(resolve(__dirname, '../../'))}:${basename(__dirname)}`; + +describe(`generator - ${generator}`, () => { + shouldSupportFeatures(Generator); + describe('blueprint support', () => testBlueprintSupport(generator)); + + describe('with defaults options', () => { + before(async () => { + await helpers.runJHipster(generator).withMockedJHipsterGenerators().withMockedSource().withSharedApplication({}).withJHipsterConfig(); + }); + + it('should match files snapshot', () => { + expect(result.getStateSnapshot()).toMatchSnapshot(); + }); + + it('should call source snapshot', () => { + expect(result.sourceCallsArg).toMatchSnapshot(); + }); + + it('should compose with generators', () => { + expect(result.composedMockedGenerators).toMatchInlineSnapshot(`[]`); + }); + }); +}); diff --git a/generators/java/generators/server/generator.ts b/generators/java/generators/server/generator.ts new file mode 100644 index 000000000000..87dd08d425fd --- /dev/null +++ b/generators/java/generators/server/generator.ts @@ -0,0 +1,130 @@ +/** + * Copyright 2013-2024 the original author or authors from the JHipster project. + * + * This file is part of the JHipster project, see https://www.jhipster.tech/ + * for more information. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import BaseApplicationGenerator from '../../../base-application/index.js'; + +const WAIT_TIMEOUT = 3 * 60000; + +export default class ServerGenerator extends BaseApplicationGenerator { + async beforeQueue() { + if (!this.fromBlueprint) { + await this.composeWithBlueprints(); + } + + if (!this.delegateToBlueprint) { + await this.dependsOnBootstrapApplication(); + } + } + + get postWriting() { + return this.asPostWritingTaskGroup({ + packageJsonScripts({ application }) { + const packageJsonConfigStorage = this.packageJson.createStorage('config').createProxy(); + (packageJsonConfigStorage as any).backend_port = application.gatewayServerPort || application.serverPort; + (packageJsonConfigStorage as any).packaging = application.defaultPackaging; + }, + packageJsonBackendScripts({ application }) { + const scriptsStorage = this.packageJson.createStorage('scripts'); + const javaCommonLog = `-Dlogging.level.ROOT=OFF -Dlogging.level.tech.jhipster=OFF -Dlogging.level.${application.packageName}=OFF`; + const javaTestLog = + '-Dlogging.level.org.springframework=OFF -Dlogging.level.org.springframework.web=OFF -Dlogging.level.org.springframework.security=OFF'; + + const buildTool = application.buildTool; + let e2ePackage = 'target/e2e'; + if (buildTool === 'maven') { + const excludeWebapp = application.skipClient ? '' : ' -Dskip.installnodenpm -Dskip.npm'; + scriptsStorage.set({ + 'app:start': './mvnw', + 'backend:info': './mvnw --version', + 'backend:doc:test': './mvnw -ntp javadoc:javadoc --batch-mode', + 'backend:nohttp:test': './mvnw -ntp checkstyle:check --batch-mode', + 'backend:start': `./mvnw${excludeWebapp}`, + 'java:jar': './mvnw -ntp verify -DskipTests --batch-mode', + 'java:war': './mvnw -ntp verify -DskipTests --batch-mode -Pwar', + 'java:docker': './mvnw -ntp verify -DskipTests -Pprod jib:dockerBuild', + 'java:docker:arm64': 'npm run java:docker -- -Djib-maven-plugin.architecture=arm64', + 'backend:unit:test': `./mvnw -ntp${excludeWebapp} verify --batch-mode ${javaCommonLog} ${javaTestLog}`, + 'backend:build-cache': './mvnw dependency:go-offline -ntp', + 'backend:debug': './mvnw -Dspring-boot.run.jvmArguments="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000"', + }); + } else if (buildTool === 'gradle') { + const excludeWebapp = application.skipClient ? '' : '-x webapp -x webapp_test'; + e2ePackage = 'e2e'; + scriptsStorage.set({ + 'app:start': './gradlew', + 'backend:info': './gradlew -v', + 'backend:doc:test': `./gradlew javadoc ${excludeWebapp}`, + 'backend:nohttp:test': `./gradlew checkstyleNohttp ${excludeWebapp}`, + 'backend:start': `./gradlew ${excludeWebapp}`, + 'java:jar': './gradlew bootJar -x test -x integrationTest', + 'java:war': './gradlew bootWar -Pwar -x test -x integrationTest', + 'java:docker': './gradlew bootJar -Pprod jibDockerBuild', + 'java:docker:arm64': 'npm run java:docker -- -PjibArchitecture=arm64', + 'backend:unit:test': `./gradlew test integrationTest ${excludeWebapp} ${javaCommonLog} ${javaTestLog}`, + 'postci:e2e:package': 'cp build/libs/*.$npm_package_config_packaging e2e.$npm_package_config_packaging', + 'backend:build-cache': + 'npm run backend:info && npm run backend:nohttp:test && npm run ci:e2e:package -- -x webapp -x webapp_test', + }); + } + + scriptsStorage.set({ + 'java:jar:dev': 'npm run java:jar -- -Pdev,webapp', + 'java:jar:prod': 'npm run java:jar -- -Pprod', + 'java:war:dev': 'npm run java:war -- -Pdev,webapp', + 'java:war:prod': 'npm run java:war -- -Pprod', + 'java:docker:dev': 'npm run java:docker -- -Pdev,webapp', + 'java:docker:prod': 'npm run java:docker -- -Pprod', + 'ci:backend:test': + 'npm run backend:info && npm run backend:doc:test && npm run backend:nohttp:test && npm run backend:unit:test -- -P$npm_package_config_default_environment', + 'ci:e2e:package': + 'npm run java:$npm_package_config_packaging:$npm_package_config_default_environment -- -Pe2e -Denforcer.skip=true', + 'preci:e2e:server:start': 'npm run services:db:await --if-present && npm run services:others:await --if-present', + 'ci:e2e:server:start': `java -jar ${e2ePackage}.$npm_package_config_packaging --spring.profiles.active=e2e,$npm_package_config_default_environment ${javaCommonLog} ${javaTestLog} --logging.level.org.springframework.web=ERROR`, + }); + }, + packageJsonE2eScripts({ application }) { + const scriptsStorage = this.packageJson.createStorage('scripts'); + const buildCmd = application.buildToolGradle ? 'gradlew' : 'mvnw -ntp'; + + let applicationWaitTimeout = WAIT_TIMEOUT * (application.applicationTypeGateway ? 2 : 1); + applicationWaitTimeout = application.authenticationTypeOauth2 ? applicationWaitTimeout * 2 : applicationWaitTimeout; + const applicationEndpoint = application.applicationTypeMicroservice + ? `http-get://127.0.0.1:${application.gatewayServerPort}/${application.endpointPrefix}/management/health/readiness` + : 'http-get://127.0.0.1:$npm_package_config_backend_port/management/health'; + scriptsStorage.set({ + 'ci:server:await': `echo "Waiting for server at port $npm_package_config_backend_port to start" && wait-on -t ${applicationWaitTimeout} ${applicationEndpoint} && echo "Server at port $npm_package_config_backend_port started"`, + }); + + // TODO add e2eTests property to application. + if (this.jhipsterConfig.testFrameworks?.includes('cypress')) { + scriptsStorage.set({ + 'pree2e:headless': 'npm run ci:server:await', + 'ci:e2e:run': 'concurrently -k -s first -n application,e2e -c red,blue npm:ci:e2e:server:start npm:e2e:headless', + 'ci:e2e:dev': `concurrently -k -s first -n application,e2e -c red,blue "./${buildCmd}" npm:e2e:headless`, + 'e2e:dev': `concurrently -k -s first -n application,e2e -c red,blue "./${buildCmd}" npm:e2e`, + 'e2e:devserver': `concurrently -k -s first -n backend,frontend,e2e -c red,yellow,blue npm:backend:start npm:start "wait-on -t ${WAIT_TIMEOUT} http-get://127.0.0.1:9000 && npm run e2e:headless -- -c baseUrl=http://localhost:9000"`, + }); + } + }, + }); + } + + get [BaseApplicationGenerator.POST_WRITING]() { + return this.delegateTasksToBlueprint(() => this.postWriting); + } +} diff --git a/generators/java/generators/server/index.ts b/generators/java/generators/server/index.ts new file mode 100644 index 000000000000..1cfadd692bb6 --- /dev/null +++ b/generators/java/generators/server/index.ts @@ -0,0 +1,20 @@ +/** + * Copyright 2013-2024 the original author or authors from the JHipster project. + * + * This file is part of the JHipster project, see https://www.jhipster.tech/ + * for more information. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { default } from './generator.js'; +export { default as command } from './command.js'; diff --git a/generators/server/generator.ts b/generators/server/generator.ts index 729b8113daad..e59ec2653df6 100644 --- a/generators/server/generator.ts +++ b/generators/server/generator.ts @@ -21,7 +21,6 @@ import { existsSync } from 'fs'; import { GENERATOR_COMMON, GENERATOR_SPRING_BOOT } from '../generator-list.js'; import BaseApplicationGenerator from '../base-application/index.js'; -import { packageJson } from '../../lib/index.js'; import { CLIENT_WEBPACK_DIR, JAVA_COMPATIBLE_VERSIONS, @@ -38,7 +37,6 @@ import { import { applicationTypes, - buildToolTypes, clientFrameworkTypes, databaseTypes, entityOptions, @@ -48,7 +46,7 @@ import { validations, } from '../../lib/jhipster/index.js'; import { stringifyApplicationData } from '../base-application/support/index.js'; -import { createNeedleCallback, mutateData } from '../base/support/index.js'; +import { mutateData } from '../base/support/index.js'; import { isReservedPaginationWords } from '../../lib/jhipster/reserved-keywords.js'; import { loadStoredAppOptions } from '../app/support/index.js'; import { isReservedH2Keyword } from '../spring-data-relational/support/h2-reserved-keywords.js'; @@ -57,7 +55,6 @@ import { hibernateSnakeCase } from './support/index.js'; const { SUPPORTED_VALIDATION_RULES } = validations; const { isReservedTableName } = reservedKeywords; const { ANGULAR, REACT, VUE } = clientFrameworkTypes; -const { GRADLE, MAVEN } = buildToolTypes; const { SQL, NO: NO_DATABASE } = databaseTypes; const { GATEWAY } = applicationTypes; @@ -70,7 +67,6 @@ const { Validations: { MAX, MIN, MAXLENGTH, MINLENGTH, MAXBYTES, MINBYTES, PATTERN }, } = validations; -const WAIT_TIMEOUT = 3 * 60000; const { NO: NO_PAGINATION } = PaginationTypes; const { NO: NO_SERVICE } = ServiceTypes; @@ -108,23 +104,6 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator { get loading() { return this.asLoadingTaskGroup({ - loadEnvironmentVariables({ application }) { - application.packageInfoJavadocs?.push( - { packageName: `${application.packageName}.aop.logging`, documentation: 'Logging aspect.' }, - { packageName: `${application.packageName}.management`, documentation: 'Application management.' }, - { packageName: `${application.packageName}.repository.rowmapper`, documentation: 'Webflux database column mapper.' }, - { packageName: `${application.packageName}.security`, documentation: 'Application security utilities.' }, - { packageName: `${application.packageName}.service.dto`, documentation: 'Data transfer objects for rest mapping.' }, - { packageName: `${application.packageName}.service.mapper`, documentation: 'Data transfer objects mappers.' }, - { packageName: `${application.packageName}.web.filter`, documentation: 'Request chain filters.' }, - { packageName: `${application.packageName}.web.rest.errors`, documentation: 'Rest layer error handling.' }, - { packageName: `${application.packageName}.web.rest.vm`, documentation: 'Rest layer visual models.' }, - ); - - if (application.defaultPackaging === 'war') { - this.log.info(`Using ${application.defaultPackaging} as default packaging`); - } - }, setupServerconsts({ application, applicationDefaults }) { // Make constants available in templates applicationDefaults({ @@ -159,8 +138,6 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator { } else { application.jhipsterDependenciesVersion = JHIPSTER_DEPENDENCIES_VERSION; } - - application.jhipsterPackageJson = packageJson; }, }); } @@ -169,28 +146,6 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator { return this.delegateTasksToBlueprint(() => this.loading); } - get preparing() { - return this.asPreparingTaskGroup({ - blockhound({ application, source }) { - source.addAllowBlockingCallsInside = ({ classPath, method }) => { - if (!application.reactive) throw new Error('Blockhound is only supported by reactive applications'); - - this.editFile( - `${application.javaPackageTestDir}config/JHipsterBlockHoundIntegration.java`, - createNeedleCallback({ - needle: 'blockhound-integration', - contentToAdd: `builder.allowBlockingCallsInside("${classPath}", "${method}");`, - }), - ); - }; - }, - }); - } - - get [BaseApplicationGenerator.PREPARING]() { - return this.delegateTasksToBlueprint(() => this.preparing); - } - get configuringEachEntity() { return this.asConfiguringEachEntityTaskGroup({ configureMicroservice({ application, entityConfig }) { @@ -426,103 +381,6 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator { return this.delegateTasksToBlueprint(() => this.default); } - get postWriting() { - return this.asPostWritingTaskGroup({ - packageJsonScripts({ application }) { - const packageJsonConfigStorage = this.packageJson.createStorage('config').createProxy(); - (packageJsonConfigStorage as any).backend_port = application.gatewayServerPort || application.serverPort; - (packageJsonConfigStorage as any).packaging = application.defaultPackaging; - }, - packageJsonBackendScripts({ application }) { - const scriptsStorage = this.packageJson.createStorage('scripts'); - const javaCommonLog = `-Dlogging.level.ROOT=OFF -Dlogging.level.tech.jhipster=OFF -Dlogging.level.${application.packageName}=OFF`; - const javaTestLog = - '-Dlogging.level.org.springframework=OFF -Dlogging.level.org.springframework.web=OFF -Dlogging.level.org.springframework.security=OFF'; - - const buildTool = application.buildTool; - let e2ePackage = 'target/e2e'; - if (buildTool === MAVEN) { - const excludeWebapp = application.skipClient ? '' : ' -Dskip.installnodenpm -Dskip.npm'; - scriptsStorage.set({ - 'app:start': './mvnw', - 'backend:info': './mvnw --version', - 'backend:doc:test': './mvnw -ntp javadoc:javadoc --batch-mode', - 'backend:nohttp:test': './mvnw -ntp checkstyle:check --batch-mode', - 'backend:start': `./mvnw${excludeWebapp}`, - 'java:jar': './mvnw -ntp verify -DskipTests --batch-mode', - 'java:war': './mvnw -ntp verify -DskipTests --batch-mode -Pwar', - 'java:docker': './mvnw -ntp verify -DskipTests -Pprod jib:dockerBuild', - 'java:docker:arm64': 'npm run java:docker -- -Djib-maven-plugin.architecture=arm64', - 'backend:unit:test': `./mvnw -ntp${excludeWebapp} verify --batch-mode ${javaCommonLog} ${javaTestLog}`, - 'backend:build-cache': './mvnw dependency:go-offline -ntp', - 'backend:debug': './mvnw -Dspring-boot.run.jvmArguments="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000"', - }); - } else if (buildTool === GRADLE) { - const excludeWebapp = application.skipClient ? '' : '-x webapp -x webapp_test'; - e2ePackage = 'e2e'; - scriptsStorage.set({ - 'app:start': './gradlew', - 'backend:info': './gradlew -v', - 'backend:doc:test': `./gradlew javadoc ${excludeWebapp}`, - 'backend:nohttp:test': `./gradlew checkstyleNohttp ${excludeWebapp}`, - 'backend:start': `./gradlew ${excludeWebapp}`, - 'java:jar': './gradlew bootJar -x test -x integrationTest', - 'java:war': './gradlew bootWar -Pwar -x test -x integrationTest', - 'java:docker': './gradlew bootJar -Pprod jibDockerBuild', - 'java:docker:arm64': 'npm run java:docker -- -PjibArchitecture=arm64', - 'backend:unit:test': `./gradlew test integrationTest ${excludeWebapp} ${javaCommonLog} ${javaTestLog}`, - 'postci:e2e:package': 'cp build/libs/*.$npm_package_config_packaging e2e.$npm_package_config_packaging', - 'backend:build-cache': - 'npm run backend:info && npm run backend:nohttp:test && npm run ci:e2e:package -- -x webapp -x webapp_test', - }); - } - - scriptsStorage.set({ - 'java:jar:dev': 'npm run java:jar -- -Pdev,webapp', - 'java:jar:prod': 'npm run java:jar -- -Pprod', - 'java:war:dev': 'npm run java:war -- -Pdev,webapp', - 'java:war:prod': 'npm run java:war -- -Pprod', - 'java:docker:dev': 'npm run java:docker -- -Pdev,webapp', - 'java:docker:prod': 'npm run java:docker -- -Pprod', - 'ci:backend:test': - 'npm run backend:info && npm run backend:doc:test && npm run backend:nohttp:test && npm run backend:unit:test -- -P$npm_package_config_default_environment', - 'ci:e2e:package': - 'npm run java:$npm_package_config_packaging:$npm_package_config_default_environment -- -Pe2e -Denforcer.skip=true', - 'preci:e2e:server:start': 'npm run services:db:await --if-present && npm run services:others:await --if-present', - 'ci:e2e:server:start': `java -jar ${e2ePackage}.$npm_package_config_packaging --spring.profiles.active=e2e,$npm_package_config_default_environment ${javaCommonLog} ${javaTestLog} --logging.level.org.springframework.web=ERROR`, - }); - }, - packageJsonE2eScripts({ application }) { - const scriptsStorage = this.packageJson.createStorage('scripts'); - const buildCmd = application.buildToolGradle ? 'gradlew' : 'mvnw -ntp'; - - let applicationWaitTimeout = WAIT_TIMEOUT * (application.applicationTypeGateway ? 2 : 1); - applicationWaitTimeout = application.authenticationTypeOauth2 ? applicationWaitTimeout * 2 : applicationWaitTimeout; - const applicationEndpoint = application.applicationTypeMicroservice - ? `http-get://127.0.0.1:${application.gatewayServerPort}/${application.endpointPrefix}/management/health/readiness` - : 'http-get://127.0.0.1:$npm_package_config_backend_port/management/health'; - scriptsStorage.set({ - 'ci:server:await': `echo "Waiting for server at port $npm_package_config_backend_port to start" && wait-on -t ${applicationWaitTimeout} ${applicationEndpoint} && echo "Server at port $npm_package_config_backend_port started"`, - }); - - // TODO add e2eTests property to application. - if (this.jhipsterConfig.testFrameworks?.includes('cypress')) { - scriptsStorage.set({ - 'pree2e:headless': 'npm run ci:server:await', - 'ci:e2e:run': 'concurrently -k -s first -n application,e2e -c red,blue npm:ci:e2e:server:start npm:e2e:headless', - 'ci:e2e:dev': `concurrently -k -s first -n application,e2e -c red,blue "./${buildCmd}" npm:e2e:headless`, - 'e2e:dev': `concurrently -k -s first -n application,e2e -c red,blue "./${buildCmd}" npm:e2e`, - 'e2e:devserver': `concurrently -k -s first -n backend,frontend,e2e -c red,yellow,blue npm:backend:start npm:start "wait-on -t ${WAIT_TIMEOUT} http-get://127.0.0.1:9000 && npm run e2e:headless -- -c baseUrl=http://localhost:9000"`, - }); - } - }, - }); - } - - get [BaseApplicationGenerator.POST_WRITING]() { - return this.delegateTasksToBlueprint(() => this.postWriting); - } - /** * Validate the entityTableName * @return {true|string} true for a valid value or error message. diff --git a/generators/spring-boot/generator.ts b/generators/spring-boot/generator.ts index af5dc20d7ac7..4ca2e71fce28 100644 --- a/generators/spring-boot/generator.ts +++ b/generators/spring-boot/generator.ts @@ -86,6 +86,7 @@ export default class SpringBootGenerator extends BaseApplicationGenerator { await this.dependsOnJHipster(GENERATOR_SERVER); await this.dependsOnJHipster('jhipster:java:domain'); await this.dependsOnJHipster('jhipster:java:build-tool'); + await this.dependsOnJHipster('jhipster:java:server'); } } @@ -315,6 +316,19 @@ public void set${javaBeanCase(propertyName)}(${propertyType} ${propertyName}) { `, }); }, + blockhound({ application, source }) { + source.addAllowBlockingCallsInside = ({ classPath, method }) => { + if (!application.reactive) throw new Error('Blockhound is only supported by reactive applications'); + + this.editFile( + `${application.javaPackageTestDir}config/JHipsterBlockHoundIntegration.java`, + createNeedleCallback({ + needle: 'blockhound-integration', + contentToAdd: `builder.allowBlockingCallsInside("${classPath}", "${method}");`, + }), + ); + }; + }, }); }