diff --git a/generators/kotlin/generator.js b/generators/kotlin/generator.js index 42b8411ff..79d33eab7 100644 --- a/generators/kotlin/generator.js +++ b/generators/kotlin/generator.js @@ -122,6 +122,17 @@ export default class extends BaseApplicationGenerator { }); } } + + if (application.enableSwaggerCodegen) { + this.editFile( + 'build.gradle', + content => `${content} +tasks.withType(org.jetbrains.kotlin.gradle.internal.KaptGenerateStubsTask.class).configureEach { + dependsOn 'openApiGenerate' +} +`, + ); + } } }, async customizeMaven({ application, source }) { diff --git a/generators/ktlint/generator.js b/generators/ktlint/generator.js index f228ca59f..6cfb3c787 100644 --- a/generators/ktlint/generator.js +++ b/generators/ktlint/generator.js @@ -135,6 +135,17 @@ export default class extends BaseApplicationGenerator { addToBuild: true, }, ]); + + if (application.enableSwaggerCodegen) { + this.editFile( + 'build.gradle', + content => `${content} +tasks.named('runKtlintFormatOverMainSourceSet').configure { + dependsOn 'openApiGenerate' +} +`, + ); + } } else { source.addJavaDefinition({ versions: [{ name: 'ktlint-maven-plugin', version: application.javaDependencies['ktlint-maven'] }], diff --git a/generators/ktlint/templates/gradle/ktlint.gradle.ejs b/generators/ktlint/templates/gradle/ktlint.gradle.ejs index 617d78f5d..579e93a62 100644 --- a/generators/ktlint/templates/gradle/ktlint.gradle.ejs +++ b/generators/ktlint/templates/gradle/ktlint.gradle.ejs @@ -19,6 +19,10 @@ ktlint { //See more options: https://github.com/JLLeitschuh/ktlint-gradle#configuration ignoreFailures = true + filter { + include("src/main/kotlin/**") + include("src/test/kotlin/**") + } } // Reformat code before compilation diff --git a/generators/migration/generator.js b/generators/migration/generator.js index aac3b8180..8ede84a2c 100644 --- a/generators/migration/generator.js +++ b/generators/migration/generator.js @@ -4,18 +4,11 @@ import { passthrough } from '@yeoman/transform'; export default class extends BaseApplicationGenerator { get [BaseApplicationGenerator.PREPARING]() { return this.asPreparingTaskGroup({ - async source({ application, source }) { + async source({ source }) { this.delayTask(() => { - source.addAllowBlockingCallsInside = () => undefined; source.addApplicationPropertiesContent = () => undefined; source.addIntegrationTestAnnotation = () => undefined; source.addTestSpringFactory = () => undefined; - - if (application.buildToolGradle) { - // Add a noop needles for spring-gateway generator - source.addJavaDefinition = () => {}; - source.addJavaDependencies = () => {}; - } }); }, }); @@ -23,27 +16,54 @@ export default class extends BaseApplicationGenerator { get [BaseApplicationGenerator.DEFAULT]() { return this.asDefaultTaskGroup({ - async defaultTask({ application }) { - if (application.buildToolGradle) { - this.queueTransformStream( - { - name: 'updating gradle files', - filter: file => file.path.endsWith('.gradle'), - refresh: false, - }, - passthrough(file => { - file.contents = Buffer.from( - file.contents - .toString() - .replaceAll(/reportOn (.*)/g, 'testResults.from($1)') - .replaceAll('destinationDir =', 'destinationDirectory =') - .replaceAll('html.enabled =', 'html.required =') - .replaceAll('xml.enabled =', 'xml.required =') - .replaceAll('csv.enabled =', 'csv.required ='), - ); - }), - ); - } + async defaultTask() { + this.queueTransformStream( + { + name: 'updating build files', + filter: file => file.path.endsWith('.gradle') || file.path.endsWith('pom.xml'), + refresh: false, + }, + passthrough(file => { + file.contents = Buffer.from( + file.contents + .toString() + .replace('micrometer-registry-prometheus-simpleclient', 'micrometer-registry-prometheus') + .replaceAll('jakarta.', 'javax.') + .replaceAll('spring-cloud-stream-test-binder', 'spring-cloud-stream-test-support') + .replaceAll('org.hibernate.orm', 'org.hibernate') + .replaceAll('mongock-springboot-v3', 'mongock-springboot') + .replaceAll('mongodb-springdata-v4-driver', 'mongodb-springdata-v3-driver') + .replaceAll('jackson-datatype-hibernate6', 'jackson-datatype-hibernate5') + .replaceAll('org.apache.cassandra', 'com.datastax.oss') + // Gradle only + .replace('hibernate-jcache"', 'hibernate-jcache:${hibernateVersion}"') + .replace( + "excludes = ['time']", + `properties { + time = null + }`, + ) + // Maven only + .replaceAll('jakarta', '') + .replace('true', '') + .replace( + 'false', + 'Problem=org.zalando.problem.Problemfalse', + ), + ); + }), + ); + + this.queueTransformStream( + { + name: 'updating log files', + filter: file => file.path.endsWith('logback-spring.xml') || file.path.endsWith('logback.xml'), + refresh: false, + }, + passthrough(file => { + file.contents = Buffer.from(file.contents.toString().replaceAll('jakarta.', 'javax.')); + }), + ); }, }); } @@ -58,31 +78,6 @@ export default class extends BaseApplicationGenerator { scriptsStorage.delete('pree2e:headless'); } }, - async postWritingTemplateTask({ application }) { - this.editFile('src/main/resources/logback-spring.xml', contents => contents.replaceAll('jakarta.', 'javax.')); - this.editFile('src/test/resources/logback.xml', contents => contents.replaceAll('jakarta.', 'javax.')); - - if (application.buildToolGradle) { - // JHipster 8 have needles fixed - this.editFile('build.gradle', contents => contents.replaceAll('//jhipster', '// jhipster')); - if (application.databaseTypeSql) { - const { javaDependencies } = application; - this.editFile('build.gradle', contents => - contents.replace( - '\nconfigurations {', - '\nconfigurations {\n liquibaseRuntime.extendsFrom sourceSets.main.compileClasspath\n', - ), - ); - this.editFile('gradle.properties', contents => - contents - .replace(/liquibasePluginVersion=(.*)/, 'liquibasePluginVersion=2.2.2') - .replace(/(checkstyleVersion)=(.*)/, `$1=${javaDependencies.checkstyle}`) - .replace(/(noHttpCheckstyleVersion)=(.*)/, `$1=${javaDependencies['nohttp-checkstyle']}`), - ); - } - this.editFile('settings.gradle', contents => contents.replaceAll('//jhipster', '// jhipster')); - } - }, }); } diff --git a/generators/spring-boot/generator.js b/generators/spring-boot/generator.js index 969a5da83..3ce8b245c 100644 --- a/generators/spring-boot/generator.js +++ b/generators/spring-boot/generator.js @@ -9,6 +9,7 @@ import { files as serverFiles } from 'jhipster-7-templates/esm/generators/server import { convertToKotlinFile } from '../kotlin/support/files.js'; import migration from './migration.cjs'; +import { KOTLIN_TEST_SRC_DIR } from './kotlin-constants.js'; const { jhipsterConstants, jhipster7DockerContainers } = migration; const { @@ -53,26 +54,11 @@ export default class extends BaseApplicationGenerator { } get [BaseApplicationGenerator.COMPOSING]() { - const mainComposing = super.composing; return this.asComposingTaskGroup({ async composeDetekt() { await this.composeWithJHipster('jhipster-kotlin:detekt'); }, - async composeWithPostWriting() { - await this.composeWithJHipster('docker'); - - if (this.jhipsterConfigWithDefaults.applicationType === 'gateway') { - // Use gateway package.json scripts. - await this.composeWithJHipster('jhipster:spring-cloud:gateway'); - } - }, - ...mainComposing, - async composing(...args) { - const { skipPriorities } = this.options; - this.options.skipPriorities = ['postWriting']; - await mainComposing.composing.call(this, ...args); - this.options.skipPriorities = skipPriorities; - }, + ...super.composing, }); } @@ -89,8 +75,6 @@ export default class extends BaseApplicationGenerator { // Remove package-info.java files file => (file.sourceFile.includes('package-info.java') ? undefined : file), file => { - // Don't use liquibase.gradle from liquibase generator - if (['gradle/liquibase.gradle'].includes(file.sourceFile)) return undefined; // Passthrough non liquibase files if (!file.sourceFile.includes('src/main/resources/config/liquibase')) return file; // Use master.xml from jhipster 7 templates @@ -98,16 +82,13 @@ export default class extends BaseApplicationGenerator { // Use liquibase templates from liquibase generator return file.namespace === 'jhipster:liquibase' ? file : undefined; }, - // Ignore gradle convention plugins - file => (file.sourceFile.includes('buildSrc/src/main/groovy/') ? undefined : file), // Ignore files from generators file => [ 'jhipster:spring-cloud:gateway', 'jhipster:spring-cloud-stream:kafka', 'jhipster:spring-cloud-stream:pulsar', - 'jhipster:gatling', - ].includes(file.namespace) && !file.sourceFile.includes('_entityPackage_') + ].includes(file.namespace) && !file.sourceFile.includes('buildSrc') ? undefined : file, // Kotling blueprint does not implements these files @@ -123,13 +104,21 @@ export default class extends BaseApplicationGenerator { 'QuerySyntaxException.java', '_enumName_.java', '_persistClass_.java.jhi.jackson_identity_info', + '_entityClass_GatlingTest.java', ].includes(sourceBasename) ? undefined : file; }, + // Updated templates from v8 file => { - // Use v8 files due to needles - if (file.sourceFile.includes('resources/logback')) { + if (!['jhipster-kotlin:spring-boot'].includes(file.namespace)) return file; + if ( + // Use v8 files due to needles + file.sourceFile.includes('resources/logback') || + // Updated gradle stack + file.sourceFile.endsWith('.gradle') || + ['gradle.properties'].includes(basename(file.sourceFile)) + ) { return { ...file, resolvedSourceFile: this.fetchFromInstalledJHipster('server/templates/', file.sourceFile), @@ -254,6 +243,19 @@ export default class extends BaseApplicationGenerator { get [BaseApplicationGenerator.PREPARING]() { return this.asPreparingTaskGroup({ ...super.preparing, + blockhound({ application, source }) { + source.addAllowBlockingCallsInside = ({ classPath, method }) => { + if (!application.reactive) throw new Error('Blockhound is only supported by reactive applications'); + + this.editFile( + `${KOTLIN_TEST_SRC_DIR}${application.packageFolder}config/JHipsterBlockHoundIntegration.kt`, + createNeedleCallback({ + needle: 'blockhound-integration', + contentToAdd: `builder.allowBlockingCallsInside("${classPath}", "${method}")`, + }), + ); + }; + }, async preparingTemplateTask({ applicationDefaults }) { applicationDefaults({ __override__: true, @@ -267,12 +269,21 @@ export default class extends BaseApplicationGenerator { applicationDefaults({ __override__: true, - gradleVersion: '7.6.4', + gradleVersion: '8.9', }); Object.assign(application.javaDependencies, { 'spring-boot': SPRING_BOOT_VERSION, 'spring-boot-dependencies': SPRING_BOOT_VERSION, + 'archunit-junit5': '0.22.0', + liquibase: '4.15.0', + hibernate: '5.6.10.Final', + 'feign-reactor-bom': '3.3.0', + 'spring-cloud-dependencies': '2021.0.3', + 'neo4j-migrations-spring-boot-starter': '1.10.1', + }); + Object.assign(application.springBootDependencies, { + 'spring-boot-dependencies': SPRING_BOOT_VERSION, }); applicationDefaults({ @@ -444,6 +455,12 @@ export default class extends BaseApplicationGenerator { 'WebsocketSecurityConfiguration.java', 'ActivityService.java', 'ActivityDTO.java', + // jhipster:java:jib + 'docker.gradle', + // jhipster:java:code-quality + 'sonar.gradle', + // jhipster:java:openapi-generator v7.6.1 + 'swagger.gradle', ].includes(sourceBasename) ? undefined : file; @@ -519,25 +536,119 @@ export default class extends BaseApplicationGenerator { get [BaseApplicationGenerator.POST_WRITING]() { return this.asPostWritingTaskGroup({ ...super.postWriting, - addJHipsterBomDependencies: undefined, - addSpringdoc: undefined, - addSpringBootPlugin: undefined, - addFeignReactor: undefined, + addJHipsterBomDependencies({ application, source }) { + const { applicationTypeGateway, applicationTypeMicroservice, serviceDiscoveryAny, messageBrokerAny, javaDependencies } = + application; + if (applicationTypeGateway || applicationTypeMicroservice || serviceDiscoveryAny || messageBrokerAny) { + source.addJavaDependencies?.([ + { + groupId: 'org.springframework.cloud', + artifactId: 'spring-cloud-dependencies', + type: 'pom', + scope: 'import', + version: javaDependencies['spring-cloud-dependencies'], + }, + ]); + } + }, + addSpringdoc({ application, source }) { + const springdocDependency = `springdoc-openapi-${application.reactive ? 'webflux' : 'webmvc'}-core`; + source.addJavaDependencies?.([{ groupId: 'org.springdoc', artifactId: springdocDependency, version: '1.6.11' }]); + }, + async customizeDependencies({ application, source }) { + source.addJavaDefinition({ + dependencies: [ + { groupId: 'io.dropwizard.metrics', artifactId: 'metrics-core' }, + { groupId: 'org.zalando', artifactId: `problem-spring-${application.reactive ? 'webflux' : 'web'}` }, + { + groupId: 'tech.jhipster', + artifactId: 'jhipster-dependencies', + version: application.jhipsterDependenciesVersion, + type: 'pom', + scope: 'import', + }, + ], + }); + + if (application.authenticationTypeJwt) { + source.addJavaDefinition({ + dependencies: [ + { groupId: 'io.jsonwebtoken', artifactId: 'jjwt-api' }, + { groupId: 'io.jsonwebtoken', artifactId: 'jjwt-impl', scope: 'runtime' }, + { groupId: 'io.jsonwebtoken', artifactId: 'jjwt-jackson', scope: 'compile' }, + ], + }); + } else if (application.authenticationTypeOauth2) { + source.addJavaDefinition({ + dependencies: [{ groupId: 'org.springframework.boot', artifactId: 'spring-boot-starter-oauth2-resource-server' }], + }); + } + + if (application.applicationTypeGateway || application.applicationTypeMicroservice) { + source.addJavaDefinition({ + dependencies: [{ groupId: 'org.springframework.cloud', artifactId: 'spring-cloud-starter-openfeign' }], + }); + } + if (application.databaseTypeMongodb) { + source.addJavaDefinition({ + dependencies: [ + { groupId: 'org.mongodb', artifactId: 'mongodb-driver-sync' }, + ...(application.reactive ? [{ groupId: 'org.mongodb', artifactId: 'mongodb-driver-reactivestreams' }] : []), + ], + }); + } + if (application.databaseTypeCassandra) { + source.addJavaDefinition({ + dependencies: [{ groupId: 'org.cassandraunit', artifactId: 'cassandra-unit-spring' }], + }); + } + if (application.databaseTypeSql && application.reactive) { + source.addJavaDefinition({ + dependencies: [{ groupId: 'org.apache.commons', artifactId: 'commons-collections4' }], + }); + } + }, + customizeGradle({ application, source }) { + if (application.buildToolGradle) { + source.addGradleProperty({ property: 'mapstructVersion', value: application.javaDependencies.mapstruct }); + source.addGradleProperty({ property: 'springBootVersion', value: application.javaDependencies['spring-boot'] }); + if (application.databaseTypeSql) { + source.addGradleProperty({ property: 'liquibase.version', value: application.javaDependencies.liquibase }); + source.addGradleProperty({ property: 'hibernateVersion', value: application.javaDependencies.hibernate }); + source.addGradleProperty({ property: 'jaxbRuntimeVersion', value: '4.0.0' }); + } + if (application.databaseTypeCassandra) { + source.addGradleProperty({ property: 'cassandraDriverVersion', value: '4.14.1' }); + } + source.addGradleDependencies([{ groupId: 'tech.jhipster', artifactId: 'jhipster-framework', scope: 'implementation' }]); + } + }, async customizeMaven({ application, source }) { if (application.buildToolMaven) { - if (application.reactive) { - this.editFile('pom.xml', contents => - contents.replace( - '', - '', - ), - ); - } - source.addMavenDefinition({ properties: [ { property: 'modernizer-maven-plugin.version', value: application.javaDependencies['modernizer-maven-plugin'] }, { property: 'modernizer.failOnViolations', value: 'false' }, + { property: 'jaxb-runtime.version', value: '4.0.0' }, + { property: 'spring-boot.version', value: application.javaDependencies['spring-boot'] }, + { property: 'liquibase-hibernate5.version', value: application.javaDependencies.liquibase }, + { property: 'liquibase.version', value: application.javaDependencies.liquibase }, + { property: 'hibernate.version', value: application.javaDependencies.hibernate }, + ], + dependencies: [ + { + groupId: 'tech.jhipster', + artifactId: 'jhipster-framework', + additionalContent: application.reactive + ? ` + + + org.springframework + spring-webmvc + + ` + : '', + }, ], }); }