From 384a52bbafd6cac2b270105356bb958d7d4e3aae Mon Sep 17 00:00:00 2001 From: Kristof Jozsa Date: Sun, 5 Jan 2025 22:58:21 +0100 Subject: [PATCH] FINERACT-2122: Add devRun gradle task, optimize build caching, fix deprecations --- .github/workflows/build-docker-mariadb.yml | 6 +- .github/workflows/build-docker-postgresql.yml | 6 +- .github/workflows/build-tests.yml | 8 +- .github/workflows/smoke-activemq.yml | 10 +- .github/workflows/smoke-kafka.yml | 10 +- build.gradle | 106 ++++++++++++++-- .../org.apache.fineract.dependencies.gradle | 1 - custom/acme/event/externalevent/build.gradle | 8 +- custom/acme/event/starter/build.gradle | 8 +- custom/acme/loan/cob/build.gradle | 6 +- custom/acme/loan/job/build.gradle | 6 +- custom/acme/loan/processor/build.gradle | 6 +- custom/acme/loan/starter/build.gradle | 6 +- custom/acme/note/service/build.gradle | 8 +- custom/acme/note/starter/build.gradle | 8 +- fineract-accounting/build.gradle | 2 +- fineract-avro-schemas/build.gradle | 75 ++++++++++-- fineract-client/build.gradle | 103 +++++++++++----- fineract-core/build.gradle | 7 +- fineract-doc/build.gradle | 16 ++- fineract-e2e-tests-core/build.gradle | 31 +++++ fineract-provider/build.gradle | 53 ++++++++ .../src/main/resources/jpa/persistence.xml | 84 +++++++------ .../apache/fineract/TestConfiguration.java | 11 +- fineract-war/build.gradle | 115 +++++++++++++++--- gradle.properties | 4 + integration-tests/build.gradle | 12 ++ integration-tests/dependencies.gradle | 5 +- .../integrationtests/common/SearchHelper.java | 2 +- .../common/accounting/AccountRuleHelper.java | 2 +- .../common/commands/MakercheckersHelper.java | 2 +- .../products/DelinquencyBucketsHelper.java | 2 +- .../products/DelinquencyRangesHelper.java | 2 +- 33 files changed, 556 insertions(+), 175 deletions(-) diff --git a/.github/workflows/build-docker-mariadb.yml b/.github/workflows/build-docker-mariadb.yml index 00e4d164b..ab3974b80 100644 --- a/.github/workflows/build-docker-mariadb.yml +++ b/.github/workflows/build-docker-mariadb.yml @@ -26,11 +26,9 @@ jobs: run: ./gradlew --no-daemon --console=plain :fineract-provider:clean :fineract-provider:build :fineract-provider:jibDockerBuild -x test -x cucumber - name: Start the stack run: docker compose up -d - - name: Wait for stack to come up - run: sleep 500 - name: Check the stack run: docker ps - name: Check health - run: curl -f -k --retry 10 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health + run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health - name: Check info - run: (( $(curl -f -k --retry 5 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 )) + run: (( $(curl -f -k --retry 5 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 )) diff --git a/.github/workflows/build-docker-postgresql.yml b/.github/workflows/build-docker-postgresql.yml index 3cbc53d90..e6b8f2d48 100644 --- a/.github/workflows/build-docker-postgresql.yml +++ b/.github/workflows/build-docker-postgresql.yml @@ -26,11 +26,9 @@ jobs: run: ./gradlew --no-daemon --console=plain :fineract-provider:clean :fineract-provider:build :fineract-provider:jibDockerBuild -x test -x cucumber - name: Start the Standalone Stack run: docker compose -f docker-compose-postgresql.yml up -d - - name: Wait for stack to come up - run: sleep 500 - name: Check the stack run: docker ps - name: Check health - run: curl -f -k --retry 10 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health + run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health - name: Check info - run: (( $(curl -f -k --retry 5 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 )) + run: (( $(curl -f -k --retry 5 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 )) diff --git a/.github/workflows/build-tests.yml b/.github/workflows/build-tests.yml index cbf2f8782..e0d99ccd4 100644 --- a/.github/workflows/build-tests.yml +++ b/.github/workflows/build-tests.yml @@ -23,15 +23,13 @@ jobs: - name: Setup Gradle uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2 - name: Build the image - run: ./gradlew --no-daemon --console=plain :fineract-provider:clean :fineract-provider:build :fineract-provider:jibDockerBuild -x test -x cucumber + run: ./gradlew --no-daemon --console=plain :fineract-provider:clean :fineract-provider:build :fineract-provider:jibDockerBuild -x test -x cucumber -x :integration-tests:test - name: Start the Fineract stack run: docker compose -f docker-compose-postgresql-test-activemq.yml up -d - - name: Wait for stack to come up - run: sleep 400 - name: Check the stack run: docker ps - name: Check health Manager - run: curl -f -k --retry 10 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health + run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health - name: Execute tests env: BASE_URL: https://localhost:8443 @@ -43,4 +41,4 @@ jobs: EVENT_VERIFICATION_ENABLED: true ACTIVEMQ_BROKER_URL: tcp://localhost:61616 ACTIVEMQ_TOPIC_NAME: events - run: ./gradlew --no-daemon --console=plain fineract-e2e-tests-runner:cucumber --tags 'not @Skip' allureReport + run: ./gradlew --no-daemon --console=plain -x test -x :integration-tests:test fineract-e2e-tests-runner:cucumber --tags 'not @Skip' allureReport diff --git a/.github/workflows/smoke-activemq.yml b/.github/workflows/smoke-activemq.yml index 4e2bfaafd..140a05ed4 100644 --- a/.github/workflows/smoke-activemq.yml +++ b/.github/workflows/smoke-activemq.yml @@ -26,17 +26,15 @@ jobs: run: ./gradlew --no-daemon --console=plain :fineract-provider:clean :fineract-provider:build :fineract-provider:jibDockerBuild -x test -x cucumber - name: Start the ActiveMQ Stack run: docker compose -f docker-compose-postgresql-activemq.yml up --scale fineract-worker=1 -d - - name: Wait for stack to come up - run: sleep 500 - name: Check the stack run: docker ps - name: Check health Manager - run: curl -f -k --retry 10 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health + run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health - name: Check health Worker1 - run: curl -f -k --retry 10 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8444/fineract-provider/actuator/health + run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8444/fineract-provider/actuator/health - name: Check info Manager - run: (( $(curl -f -k --retry 5 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 )) + run: (( $(curl -f -k --retry 5 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 )) - name: Check info Worker1 - run: (( $(curl -f -k --retry 5 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8444/fineract-provider/actuator/info | wc --chars) > 100 )) + run: (( $(curl -f -k --retry 5 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8444/fineract-provider/actuator/info | wc --chars) > 100 )) - name: Run Smoke Test with Remote COB run: ./gradlew --no-daemon --console=plain :integration-tests:cleanTest :integration-tests:test --tests "org.apache.fineract.integrationtests.investor.externalassetowner.InitiateExternalAssetOwnerTransferTest.saleActiveLoanToExternalAssetOwnerAndBuybackADayLater" -PcargoDisabled diff --git a/.github/workflows/smoke-kafka.yml b/.github/workflows/smoke-kafka.yml index 1233b5520..76c4ed2c9 100644 --- a/.github/workflows/smoke-kafka.yml +++ b/.github/workflows/smoke-kafka.yml @@ -26,17 +26,15 @@ jobs: run: ./gradlew --no-daemon --console=plain :fineract-provider:clean :fineract-provider:build :fineract-provider:jibDockerBuild -x test -x cucumber - name: Start the Kafka Stack run: docker compose -f docker-compose-postgresql-kafka.yml up --scale fineract-worker=1 -d - - name: Wait for stack to come up - run: sleep 500 - name: Check the stack run: docker ps - name: Check health Manager - run: curl -f -k --retry 10 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health + run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health - name: Check health Worker1 - run: curl -f -k --retry 10 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8444/fineract-provider/actuator/health + run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8444/fineract-provider/actuator/health - name: Check info Manager - run: (( $(curl -f -k --retry 5 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 )) + run: (( $(curl -f -k --retry 5 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 )) - name: Check info Worker1 - run: (( $(curl -f -k --retry 5 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8444/fineract-provider/actuator/info | wc --chars) > 100 )) + run: (( $(curl -f -k --retry 5 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8444/fineract-provider/actuator/info | wc --chars) > 100 )) - name: Run Smoke Test with Remote COB run: ./gradlew --no-daemon --console=plain :integration-tests:cleanTest :integration-tests:test --tests "org.apache.fineract.integrationtests.investor.externalassetowner.InitiateExternalAssetOwnerTransferTest.saleActiveLoanToExternalAssetOwnerAndBuybackADayLater" -PcargoDisabled diff --git a/build.gradle b/build.gradle index ad23be811..f743d4efc 100644 --- a/build.gradle +++ b/build.gradle @@ -150,11 +150,39 @@ allprojects { mavenCentral() } + configurations { + api { + canBeResolved = true + } + } + apply plugin: 'com.adarshr.test-logger' apply plugin: 'com.diffplug.spotless' apply plugin: 'com.github.hierynomus.license' + apply plugin: 'net.ltgt.errorprone' + + tasks.withType(JavaCompile).configureEach { + options.errorprone { + disableWarningsInGeneratedCode = true + disable( + "CanIgnoreReturnValueSuggester", + "SameNameButDifferent", // Until errorprone recognizes Lombok + "MultiVariableDeclaration", // Until errorprone recognizes Lombok + "UnnecessaryDefaultInEnumSwitch", // FINERACT-1911 + "AssertEqualsArgumentOrderChecker", + "RemoveUnusedImports" // For generated code + ) + error( + "DefaultCharset", + "StringSplitter", + "MutablePublicArray", + "EqualsGetClass", + "FutureReturnValueIgnored" + ) + } + } + apply plugin: 'org.nosphere.apache.rat' - apply plugin: 'project-report' apply plugin: 'com.github.jk1.dependency-license-report' // Configuration for the sonarqube plugin is now in GitHub Actions @@ -324,10 +352,49 @@ configure(project.fineractJavaProjects) { apply plugin: 'java' apply plugin: 'idea' + + java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + withSourcesJar() + withJavadocJar() + } + + tasks.withType(ProcessResources) { + destinationDir = layout.buildDirectory.dir('classes/java/main').get().asFile + } + + // Add performance optimizations + configurations.all { + resolutionStrategy { + cacheChangingModulesFor 0, 'seconds' + cacheDynamicVersionsFor 0, 'seconds' + } + } + + tasks.withType(JavaCompile).configureEach { + options.incremental = true + options.fork = true + outputs.cacheIf { true } + options.compilerArgs << '-parameters' + options.encoding = 'UTF-8' + options.compilerArgs << '-Xlint:unchecked' + options.compilerArgs << '-Xlint:deprecation' + if (project.hasProperty('warnings') && project.warnings.contains('fail')) { + options.compilerArgs << '-Werror' + } + if (project.hasProperty('warnings') && project.warnings.contains('none')) { + options.compilerArgs << '-nowarn' + } + if (project.plugins.hasPlugin('org.springframework.boot')) { + options.generatedSourceOutputDirectory = file("$buildDir/generated/sources/annotationProcessor/java/main") + } + options.generatedSourceOutputDirectory = file("$buildDir/generated/sources/annotationProcessor/java/main") + } + apply plugin: 'eclipse' apply plugin: 'checkstyle' apply plugin: 'jacoco' - apply plugin: 'net.ltgt.errorprone' apply plugin: 'com.github.spotbugs' apply plugin: 'com.github.andygoossens.modernizer' apply from: "${rootDir}/buildSrc/src/main/groovy/org.apache.fineract.dependencies.gradle" @@ -335,9 +402,9 @@ configure(project.fineractJavaProjects) { group = 'org.apache.fineract' /* define the valid syntax level for source files */ - sourceCompatibility = JavaVersion.VERSION_17 - /* define binary compatibility version */ - targetCompatibility = JavaVersion.VERSION_17 + // sourceCompatibility = JavaVersion.VERSION_17 + // /* define binary compatibility version */ + // targetCompatibility = JavaVersion.VERSION_17 /* http://stackoverflow.com/questions/19653311/jpa-repository-works-in-idea-and-production-but-not-in-gradle */ sourceSets.main.output.resourcesDir = sourceSets.main.java.classesDirectory @@ -353,7 +420,6 @@ configure(project.fineractJavaProjects) { } configurations { - implementation.setCanBeResolved(true) api.setCanBeResolved(true) } tasks.withType(Copy) { @@ -361,10 +427,8 @@ configure(project.fineractJavaProjects) { } tasks.withType(JavaCompile) { options.compilerArgs += [ - "-Xlint:unchecked", "-Xlint:cast", "-Xlint:auxiliaryclass", - "-Xlint:deprecation", "-Xlint:dep-ann", "-Xlint:divzero", "-Xlint:empty", @@ -398,6 +462,10 @@ configure(project.fineractJavaProjects) { options.deprecation = true } + check { + dependsOn(rat, licenseMain, licenseTest) + } + dependencies { spotbugsPlugins 'jp.skypencil.findbugs.slf4j:bug-pattern:1.5.0@jar' } @@ -469,7 +537,7 @@ configure(project.fineractJavaProjects) { reports { html.required = true xml.required = true - html.destination file("${buildDir}/code-coverage") + html.outputLocation = layout.buildDirectory.dir('code-coverage') } } @@ -479,11 +547,12 @@ configure(project.fineractJavaProjects) { errorprone "com.google.errorprone:error_prone_core:2.35.1" } - tasks.withType(JavaCompile) { + tasks.withType(JavaCompile).configureEach { options.errorprone { enabled = project.gradle.startParameter.taskNames.contains('build') || project.gradle.startParameter.taskNames.contains('check') - disableWarningsInGeneratedCode = true - excludedPaths = ".*/build/.*" + if (project.path == ':fineract-client') { + excludedPaths = '.*/build/generated/java/src/main/java/.*' + } disable( // TODO Remove disabled checks from this list, by fixing remaining usages "UnusedVariable", @@ -669,6 +738,19 @@ configure(project.fineractJavaProjects) { 'java/util/Optional.get:()Ljava/lang/Object;' // Disable forcing the usage of Optional.orElseThrow(java.util.function.Supplier) ] } + + tasks.withType(Javadoc) { + options.addStringOption('Xdoclint:none', '-quiet') + options.encoding = 'UTF-8' + // Disable strict checking to prevent build failures on invalid javadoc + options.addBooleanOption('html5', true) + // Add this if you're using Java 17 records or other modern features + if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17)) { + options.addBooleanOption('html5', true) + } + // Ignore any errors during javadoc generation + failOnError = false + } } configure(project.fineractCustomProjects) { diff --git a/buildSrc/src/main/groovy/org.apache.fineract.dependencies.gradle b/buildSrc/src/main/groovy/org.apache.fineract.dependencies.gradle index 2e4b1c5a4..277a25548 100644 --- a/buildSrc/src/main/groovy/org.apache.fineract.dependencies.gradle +++ b/buildSrc/src/main/groovy/org.apache.fineract.dependencies.gradle @@ -130,7 +130,6 @@ dependencyManagement { dependency 'org.mock-server:mockserver-junit-jupiter:5.15.0' dependency 'org.webjars:webjars-locator-core:0.59' dependency 'com.icegreen:greenmail-junit5:2.0.1' - dependency 'com.intuit.karate:karate-junit5:1.4.1' // fineract client dependencies dependency "com.squareup.retrofit2:retrofit:2.11.0" diff --git a/custom/acme/event/externalevent/build.gradle b/custom/acme/event/externalevent/build.gradle index bb703fb8a..57ad8a7a4 100644 --- a/custom/acme/event/externalevent/build.gradle +++ b/custom/acme/event/externalevent/build.gradle @@ -16,10 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -description = 'ACME Corp.: Fineract external events' +description = 'ACME Fineract Event External Event' -group = 'com.acme.fineract.event' +group = 'com.acme.fineract' -archivesBaseName = 'acme-fineract-event-externalevent' +base { + archivesName = 'acme-fineract-event-externalevent' +} apply from: 'dependencies.gradle' diff --git a/custom/acme/event/starter/build.gradle b/custom/acme/event/starter/build.gradle index 314a45cf4..a8981a976 100644 --- a/custom/acme/event/starter/build.gradle +++ b/custom/acme/event/starter/build.gradle @@ -16,10 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -description = 'ACME Corp.: Fineract Event Starter' +description = 'ACME Fineract Event Starter' -group = 'com.acme.fineract.event' +group = 'com.acme.fineract' -archivesBaseName = 'acme-fineract-event-starter' +base { + archivesName = 'acme-fineract-event-starter' +} apply from: 'dependencies.gradle' diff --git a/custom/acme/loan/cob/build.gradle b/custom/acme/loan/cob/build.gradle index 04ca760dc..a9ab50888 100644 --- a/custom/acme/loan/cob/build.gradle +++ b/custom/acme/loan/cob/build.gradle @@ -16,10 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -description = 'ACME Corp.: Fineract COB Loan' +description = 'ACME Fineract Loan COB' group = 'com.acme.fineract' -archivesBaseName = 'acme-fineract-loan-cob' +base { + archivesName = 'acme-fineract-loan-cob' +} apply from: 'dependencies.gradle' diff --git a/custom/acme/loan/job/build.gradle b/custom/acme/loan/job/build.gradle index 235711ad7..d021b213a 100644 --- a/custom/acme/loan/job/build.gradle +++ b/custom/acme/loan/job/build.gradle @@ -16,10 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -description = 'ACME Corp.: Fineract Loan Job' +description = 'ACME Fineract Loan Job' group = 'com.acme.fineract' -archivesBaseName = 'acme-fineract-loan-job' +base { + archivesName = 'acme-fineract-loan-job' +} apply from: 'dependencies.gradle' diff --git a/custom/acme/loan/processor/build.gradle b/custom/acme/loan/processor/build.gradle index c693255c9..6ff821a31 100644 --- a/custom/acme/loan/processor/build.gradle +++ b/custom/acme/loan/processor/build.gradle @@ -16,10 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -description = 'ACME Corp.: Fineract Loan Transaction Processors' +description = 'ACME Fineract Loan Processor' group = 'com.acme.fineract' -archivesBaseName = 'acme-fineract-loan-processor' +base { + archivesName = 'acme-fineract-loan-processor' +} apply from: 'dependencies.gradle' diff --git a/custom/acme/loan/starter/build.gradle b/custom/acme/loan/starter/build.gradle index 8620f5bfd..41e4b85eb 100644 --- a/custom/acme/loan/starter/build.gradle +++ b/custom/acme/loan/starter/build.gradle @@ -16,10 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -description = 'ACME Corp.: Fineract COB Starter' +description = 'ACME Fineract Loan Starter' group = 'com.acme.fineract' -archivesBaseName = 'acme-fineract-loan-starter' +base { + archivesName = 'acme-fineract-loan-starter' +} apply from: 'dependencies.gradle' diff --git a/custom/acme/note/service/build.gradle b/custom/acme/note/service/build.gradle index 90fdb314f..2c3adebbb 100644 --- a/custom/acme/note/service/build.gradle +++ b/custom/acme/note/service/build.gradle @@ -16,10 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -description = 'ACME Corp.: Fineract Note Service' +description = 'ACME Fineract Note Service' -group = 'com.acme.fineract.portfolio.note' +group = 'com.acme.fineract' -archivesBaseName = 'acme-fineract-note-service' +base { + archivesName = 'acme-fineract-note-service' +} apply from: 'dependencies.gradle' diff --git a/custom/acme/note/starter/build.gradle b/custom/acme/note/starter/build.gradle index 49bf235b5..2fb605798 100644 --- a/custom/acme/note/starter/build.gradle +++ b/custom/acme/note/starter/build.gradle @@ -16,10 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -description = 'ACME Corp.: Fineract Note Starter' +description = 'ACME Fineract Note Starter' -group = 'com.acme.fineract.portfolio.note' +group = 'com.acme.fineract' -archivesBaseName = 'acme-fineract-note-starter' +base { + archivesName = 'acme-fineract-note-starter' +} apply from: 'dependencies.gradle' diff --git a/fineract-accounting/build.gradle b/fineract-accounting/build.gradle index 3018795aa..916069b1f 100644 --- a/fineract-accounting/build.gradle +++ b/fineract-accounting/build.gradle @@ -31,7 +31,7 @@ compileJava.doLast { javaexec { description = 'Performs EclipseLink static weaving of entity classes' def target = source - main 'org.eclipse.persistence.tools.weaving.jpa.StaticWeave' + mainClass = 'org.eclipse.persistence.tools.weaving.jpa.StaticWeave' args '-persistenceinfo', source, source, target classpath sourceSets.main.runtimeClasspath } diff --git a/fineract-avro-schemas/build.gradle b/fineract-avro-schemas/build.gradle index ea2051dd3..5afaaec48 100644 --- a/fineract-avro-schemas/build.gradle +++ b/fineract-avro-schemas/build.gradle @@ -26,18 +26,39 @@ apply plugin: 'com.github.davidmc24.gradle.plugin.avro-base' apply from: 'dependencies.gradle' -task preprocessAvroSchemas() { - doLast { - copy { - from "$projectDir/src/main/avro" - into "$buildDir/generated/avro/src/main/avro" - filter { line -> - line.replaceAll("\"bigdecimal\"", new File("$projectDir/src/main/resources/avro-templates/bigdecimal.avsc").getText("UTF-8")) +abstract class PreprocessAvroSchemasTask extends DefaultTask { + @InputDirectory + abstract DirectoryProperty getInputDir() + + @InputFile + abstract RegularFileProperty getBigDecimalTemplate() + + @OutputDirectory + abstract DirectoryProperty getOutputDir() + + @TaskAction + def preprocess() { + def template = getBigDecimalTemplate().get().asFile.getText("UTF-8") + def input = getInputDir().get().asFile + def output = getOutputDir().get().asFile + + input.eachFileRecurse { file -> + if (file.isFile()) { + def relativePath = input.toPath().relativize(file.toPath()) + def targetFile = output.toPath().resolve(relativePath).toFile() + targetFile.parentFile.mkdirs() + targetFile.text = file.text.replaceAll("\"bigdecimal\"", template) } } } } +tasks.register('preprocessAvroSchemas', PreprocessAvroSchemasTask) { + inputDir = file("$projectDir/src/main/avro") + bigDecimalTemplate = file("$projectDir/src/main/resources/avro-templates/bigdecimal.avsc") + outputDir = file("$buildDir/generated/avro/src/main/avro") +} + task buildJavaSdk(type: GenerateAvroJavaTask) { source("$buildDir/generated/avro/src/main/avro") outputDir = file("$buildDir/generated/java/src/main/java") @@ -53,7 +74,33 @@ spotless { } buildJavaSdk.dependsOn(preprocessAvroSchemas, spotlessJsonApply) -compileJava.dependsOn(buildJavaSdk, licenseFormatMain) + +sourceSets { + main { + java { + srcDir file("$buildDir/generated/java/src/main/java") + } + resources { + srcDir file("$projectDir/src/main/resources") + srcDir file("$projectDir/src/main/avro") + } + output.dir(file("$buildDir/generated/java/src/main/java"), builtBy: 'buildJavaSdk') + } +} + +jar { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + from sourceSets.main.output + from("$buildDir/generated/java/src/main/java") { + include "**/*.java" + } +} + +compileJava { + dependsOn buildJavaSdk + source = sourceSets.main.java.srcDirs + options.compilerArgs += ['-parameters'] +} java { // keep this at Java 8, not 17 @@ -61,7 +108,10 @@ java { targetCompatibility = JavaVersion.VERSION_1_8 } -tasks.withType(JavaCompile) { +tasks.withType(JavaCompile).configureEach { + options.errorprone { + enabled = false // Disable ErrorProne for this module since it contains generated code + } options.compilerArgs -= ["-Werror"] } @@ -74,7 +124,10 @@ test { useJUnitPlatform() } -sourceSets.main.java.srcDir new File(buildDir, "generated/java/src/main/java") - licenseFormatMain.dependsOn buildJavaSdk licenseMain.dependsOn licenseFormatMain + +tasks.named('sourcesJar') { + dependsOn tasks.named('buildJavaSdk') + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} diff --git a/fineract-client/build.gradle b/fineract-client/build.gradle index 485493e18..a079f0a08 100644 --- a/fineract-client/build.gradle +++ b/fineract-client/build.gradle @@ -107,29 +107,83 @@ task buildAsciidoc(type: org.openapitools.generator.gradle.plugin.tasks.Generate dependsOn(':fineract-provider:resolve') } +// Configure source sets with proper output directories +sourceSets { + main { + java { + srcDir new File(buildDir, "generated/java/src/main/java") + destinationDirectory = layout.buildDirectory.dir('classes/java/main').get().asFile + } + output.resourcesDir = layout.buildDirectory.dir('resources/main').get().asFile + } + test { + java { + destinationDirectory = layout.buildDirectory.dir('classes/java/test').get().asFile + } + output.resourcesDir = layout.buildDirectory.dir('resources/test').get().asFile + } +} + +// Configure jar tasks to handle duplicates +tasks.withType(Jar).configureEach { + // Handle duplicates by using the first occurrence + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} + +// Improve the cleanup task to track inputs and outputs task cleanupGeneratedJavaFiles() { + def tempDir = file("$buildDir/generated/temp-java") + def targetDir = file("$buildDir/generated/java") + + inputs.dir(tempDir) + outputs.dir(targetDir) + doLast { copy { - from "$buildDir/generated/temp-java".toString() - into "$buildDir/generated/java".toString() + from tempDir + into targetDir filter { line -> line - // This is a temporary step to get rid of joda imports in the generated code - // At this point it's unknown why it's even generated, probably it's a bug in the generator - .replaceAll("import org\\.joda\\.time\\.\\*;", "") - // The 3 lines below handles the cases when a request body is not required - .replaceAll(", \\)", ")") - .replaceAll(", , @HeaderMap", ", @HeaderMap") - .replaceAll("\\(, ", "(") + .replaceAll("import org\\.joda\\.time\\.\\*;", "") + .replaceAll(", \\)", ")") + .replaceAll(", , @HeaderMap", ", @HeaderMap") + .replaceAll("\\(, ", "(") } + // Also set duplicates strategy for the copy task + duplicatesStrategy = DuplicatesStrategy.EXCLUDE } } - dependsOn("buildJavaSdk") } -// TODO: @vidakovic we could provide even more client libs in different languages (Go, Ruby, Swift etc.) -compileJava.dependsOn(buildJavaSdk, buildTypescriptAngularSdk, buildAsciidoc, cleanupGeneratedJavaFiles, licenseFormatMain, spotlessMiscApply) +// Configure Java compilation +tasks.named('compileJava') { + outputs.cacheIf { true } + dependsOn(buildJavaSdk, buildTypescriptAngularSdk, buildAsciidoc, cleanupGeneratedJavaFiles, licenseFormatMain, spotlessMiscApply) + mustRunAfter(licenseFormatMain, cleanupGeneratedJavaFiles) +} + +// Configure sources jar task +tasks.named('sourcesJar') { + dependsOn(cleanupGeneratedJavaFiles) + mustRunAfter(cleanupGeneratedJavaFiles) + + from(sourceSets.main.java.srcDirs) { + include "**/*.java" + } +} + +// Configure license formatting +tasks.named('licenseFormatMain') { + dependsOn(cleanupGeneratedJavaFiles) + mustRunAfter(cleanupGeneratedJavaFiles) + source = sourceSets.main.java.srcDirs +} + +tasks.named('licenseMain') { + dependsOn(licenseFormatMain) + mustRunAfter(licenseFormatMain) +} java { // keep this at Java 8, not 17; see https://issues.apache.org/jira/browse/FINERACT-1214 @@ -137,26 +191,17 @@ java { targetCompatibility = JavaVersion.VERSION_1_8 } -tasks.withType(JavaCompile) { - // the generated code in build/generated/java/src/main/java/org/apache/fineract/client/auth/OAuthOkHttpClient.java#L71 currently uses deprecated RequestBody.create(MediaType,String) - // TODO FINERACT-1247 why does this not work: - // options.compilerArgs -= ["-Xlint:deprecation"] - // options.compilerArgs += ["-Xlint:-deprecation"] - // So we just have to use: - options.compilerArgs -= ["-Werror"] -} - -configurations { - generatedCompileClasspath.extendsFrom implementation - generatedRuntimeClasspath.extendsFrom runtimeClasspath +tasks.withType(JavaCompile).configureEach { + options.errorprone { + excludedPaths = '.*/build/generated/java/src/main/java/.*' + } } test { useJUnitPlatform() } -sourceSets.main.java.srcDir new File(buildDir, "generated/java/src/main/java") - -// NOTE: Gradle suggested these dependencies -licenseFormatMain.dependsOn buildJavaSdk -licenseMain.dependsOn licenseFormatMain +configurations { + generatedCompileClasspath.extendsFrom implementation + generatedRuntimeClasspath.extendsFrom runtimeClasspath +} diff --git a/fineract-core/build.gradle b/fineract-core/build.gradle index f02abf9a6..5a46fa767 100644 --- a/fineract-core/build.gradle +++ b/fineract-core/build.gradle @@ -31,7 +31,7 @@ compileJava.doLast { javaexec { description = 'Performs EclipseLink static weaving of entity classes' def target = source - main 'org.eclipse.persistence.tools.weaving.jpa.StaticWeave' + mainClass = 'org.eclipse.persistence.tools.weaving.jpa.StaticWeave' args '-persistenceinfo', source, '-classpath', sourceSets.main.runtimeClasspath, source, target classpath sourceSets.main.runtimeClasspath } @@ -63,6 +63,11 @@ configurations { apply from: 'dependencies.gradle' +compileJava { + dependsOn ':fineract-avro-schemas:jar' + options.compilerArgs += ['-parameters'] +} + // Configuration for the modernizer plugin // https://github.com/andygoossens/gradle-modernizer-plugin modernizer { diff --git a/fineract-doc/build.gradle b/fineract-doc/build.gradle index 4338bc29b..0504c6ed8 100644 --- a/fineract-doc/build.gradle +++ b/fineract-doc/build.gradle @@ -25,8 +25,8 @@ asciidoctorj { attributes = [ version: "${project.version}", generated: "${buildDir}/generated/asciidoc", - imagesdir: "${projectDir}/src/docs/en/images", - diagramsdir: "${projectDir}/src/docs/en/diagrams", + imagesdir: "${buildDir}/generated/images", + diagramsdir: "${buildDir}/generated/diagrams", years: '2015-2024', revnumber: "${project.version}".toString(), rootdir: "${rootDir}".toString(), @@ -59,6 +59,16 @@ asciidoctor { dependsOn(':fineract-client:clean', ':fineract-client:buildAsciidoc') } +task copyImages(type: Copy) { + from "${projectDir}/src/docs/en/images" + into "${buildDir}/generated/images" +} + +task copyDiagrams(type: Copy) { + from "${projectDir}/src/docs/en/diagrams" + into "${buildDir}/generated/diagrams" +} + asciidoctorPdf { languages 'en' @@ -71,6 +81,8 @@ asciidoctorPdf { logging.captureStandardError LogLevel.INFO + dependsOn copyImages, copyDiagrams + // TODO: @vidakovic prepare a nicer theme // theme 'fineract-default' // pdfThemes { diff --git a/fineract-e2e-tests-core/build.gradle b/fineract-e2e-tests-core/build.gradle index 14ccb5ff3..b5d1e35bd 100644 --- a/fineract-e2e-tests-core/build.gradle +++ b/fineract-e2e-tests-core/build.gradle @@ -21,10 +21,41 @@ plugins { id 'java' } +// Configure source sets with proper output directories +sourceSets { + test { + java { + destinationDirectory = layout.buildDirectory.dir('classes/java/test').get().asFile + } + resources { + destinationDirectory = layout.buildDirectory.dir('resources/test').get().asFile + } + } +} + repositories { mavenCentral() } +// Configure test compilation +tasks.named('compileTestJava') { + description = 'Compiles test Java source files' + + // Enable caching + outputs.cacheIf { true } + + // Configure compiler options + options.compilerArgs.add("-parameters") + + // Ensure proper output tracking + outputs.dir(sourceSets.test.java.destinationDirectory) + .withPropertyName("testClassesDir") + + // Track annotation processor outputs + options.annotationProcessorGeneratedSourcesDirectory = + layout.buildDirectory.dir('generated/sources/annotationProcessor/java/test').get().asFile +} + dependencies { testImplementation(project(':fineract-avro-schemas')) testImplementation(project(':fineract-client')) diff --git a/fineract-provider/build.gradle b/fineract-provider/build.gradle index 8f4f2121e..755ac5f32 100644 --- a/fineract-provider/build.gradle +++ b/fineract-provider/build.gradle @@ -82,6 +82,11 @@ resolve { configurations { providedRuntime // needed for Spring Boot executable WAR providedCompile + implementation + testImplementation + cucumberRuntime { + extendsFrom testImplementation + } compile() { exclude module: 'hibernate-entitymanager' exclude module: 'hibernate-validator' @@ -100,6 +105,16 @@ configurations { runtime } +dependencies { + implementation project(':fineract-core') + implementation 'org.springframework.boot:spring-boot-starter-test' + implementation 'org.mockito:mockito-core' + implementation 'org.mockito:mockito-junit-jupiter' + implementation 'org.junit.jupiter:junit-jupiter-api' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.liquibase:liquibase-core' +} + apply from: 'dependencies.gradle' // Configuration for the modernizer plugin @@ -352,3 +367,41 @@ spotbugsTest.dependsOn resolve compileTestJava.dependsOn ':fineract-client:processResources', ':fineract-avro-schemas:processResources' resolveMainClassName.dependsOn resolve processResources.dependsOn compileJava + +javadoc { + dependsOn resolve +} + +task devRun(type: org.springframework.boot.gradle.tasks.run.BootRun) { + description = 'Runs the application quickly for development by skipping quality checks' + group = 'Application' + + // Configure the build to skip quality checks + gradle.taskGraph.whenReady { graph -> + if (graph.hasTask(devRun)) { + tasks.matching { task -> + task.name in ['checkstyle', 'checkstyleMain', 'checkstyleTest', + 'spotlessCheck', 'spotlessApply', + 'spotbugsMain', 'spotbugsTest', + 'javadoc', 'javadocJar', + 'modernizer', + 'testClasses'] + }.configureEach { + enabled = false + } + // Also disable error prone compilation flags + tasks.withType(JavaCompile).configureEach { + options.errorprone.enabled = false + } + } + } + + // Inherit all bootRun settings + classpath = bootRun.classpath + mainClass = bootRun.mainClass + jvmArgs = bootRun.jvmArgs + + doFirst { + println "Running in development mode - quality checks are disabled" + } +} diff --git a/fineract-provider/src/main/resources/jpa/persistence.xml b/fineract-provider/src/main/resources/jpa/persistence.xml index 4419151df..64d3e7e7b 100644 --- a/fineract-provider/src/main/resources/jpa/persistence.xml +++ b/fineract-provider/src/main/resources/jpa/persistence.xml @@ -32,45 +32,45 @@ org.apache.fineract.accounting.glaccount.domain.GLAccount org.apache.fineract.accounting.journalentry.domain.JournalEntry - org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom - org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom org.apache.fineract.infrastructure.codes.domain.Code org.apache.fineract.infrastructure.codes.domain.CodeValue + org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom + org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom org.apache.fineract.infrastructure.documentmanagement.domain.Image - org.apache.fineract.organisation.staff.domain.Staff - org.apache.fineract.organisation.office.domain.Office - org.apache.fineract.organisation.monetary.domain.OrganisationCurrency - org.apache.fineract.organisation.monetary.domain.ApplicationCurrency org.apache.fineract.organisation.holiday.domain.Holiday + org.apache.fineract.organisation.monetary.domain.ApplicationCurrency + org.apache.fineract.organisation.monetary.domain.OrganisationCurrency + org.apache.fineract.organisation.office.domain.Office + org.apache.fineract.organisation.staff.domain.Staff org.apache.fineract.organisation.workingdays.domain.WorkingDays - org.apache.fineract.portfolio.group.domain.Group - org.apache.fineract.portfolio.group.domain.GroupLevel - org.apache.fineract.portfolio.group.domain.StaffAssignmentHistory - org.apache.fineract.portfolio.group.domain.GroupRole - org.apache.fineract.portfolio.client.domain.Client - org.apache.fineract.portfolio.client.domain.ClientIdentifier - org.apache.fineract.portfolio.rate.domain.Rate - org.apache.fineract.portfolio.fund.domain.Fund - org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket - org.apache.fineract.portfolio.delinquency.domain.DelinquencyRange - org.apache.fineract.portfolio.paymenttype.domain.PaymentType - org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail - org.apache.fineract.portfolio.floatingrates.domain.FloatingRate - org.apache.fineract.portfolio.floatingrates.domain.FloatingRatePeriod org.apache.fineract.portfolio.calendar.domain.Calendar org.apache.fineract.portfolio.calendar.domain.CalendarHistory org.apache.fineract.portfolio.calendar.domain.CalendarInstance + org.apache.fineract.portfolio.client.domain.Client + org.apache.fineract.portfolio.client.domain.ClientIdentifier + org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket + org.apache.fineract.portfolio.delinquency.domain.DelinquencyRange + org.apache.fineract.portfolio.floatingrates.domain.FloatingRate + org.apache.fineract.portfolio.floatingrates.domain.FloatingRatePeriod + org.apache.fineract.portfolio.fund.domain.Fund + org.apache.fineract.portfolio.group.domain.Group + org.apache.fineract.portfolio.group.domain.GroupLevel + org.apache.fineract.portfolio.group.domain.GroupRole + org.apache.fineract.portfolio.group.domain.StaffAssignmentHistory + org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail + org.apache.fineract.portfolio.paymenttype.domain.PaymentType + org.apache.fineract.portfolio.rate.domain.Rate org.apache.fineract.useradministration.domain.AppUser - org.apache.fineract.useradministration.domain.Role - org.apache.fineract.useradministration.domain.Permission org.apache.fineract.useradministration.domain.AppUserClientMapping + org.apache.fineract.useradministration.domain.Permission + org.apache.fineract.useradministration.domain.Role org.apache.fineract.investor.domain.ExternalAssetOwner - org.apache.fineract.investor.domain.ExternalAssetOwnerTransfer - org.apache.fineract.investor.domain.ExternalAssetOwnerTransferLoanMapping - org.apache.fineract.investor.domain.ExternalAssetOwnerTransferDetails org.apache.fineract.investor.domain.ExternalAssetOwnerJournalEntryMapping + org.apache.fineract.investor.domain.ExternalAssetOwnerTransfer + org.apache.fineract.investor.domain.ExternalAssetOwnerTransferDetails org.apache.fineract.investor.domain.ExternalAssetOwnerTransferJournalEntryMapping + org.apache.fineract.investor.domain.ExternalAssetOwnerTransferLoanMapping org.apache.fineract.portfolio.collateral.domain.LoanCollateral org.apache.fineract.portfolio.collateralmanagement.domain.ClientCollateralManagement @@ -79,13 +79,13 @@ org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyAction org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyTagHistory org.apache.fineract.portfolio.delinquency.domain.LoanInstallmentDelinquencyTag - org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeParameter org.apache.fineract.portfolio.loanaccount.domain.GroupLoanIndividualMonitoringAccount org.apache.fineract.portfolio.loanaccount.domain.Loan org.apache.fineract.portfolio.loanaccount.domain.LoanCharge org.apache.fineract.portfolio.loanaccount.domain.LoanChargePaidBy org.apache.fineract.portfolio.loanaccount.domain.LoanCollateralManagement org.apache.fineract.portfolio.loanaccount.domain.LoanCreditAllocationRule + org.apache.fineract.portfolio.loanaccount.domain.LoanCreditAllocationRule org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails org.apache.fineract.portfolio.loanaccount.domain.LoanInstallmentCharge org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails @@ -103,6 +103,14 @@ org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelation org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping + org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeParameter + org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeParameter + org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest + org.apache.fineract.portfolio.loanproduct.domain.AllocationType + org.apache.fineract.portfolio.loanproduct.domain.AllocationTypeListConverter + org.apache.fineract.portfolio.loanproduct.domain.CreditAllocationTransactionType + org.apache.fineract.portfolio.loanproduct.domain.DueType + org.apache.fineract.portfolio.loanproduct.domain.FutureInstallmentAllocationRule org.apache.fineract.portfolio.loanproduct.domain.LoanProduct org.apache.fineract.portfolio.loanproduct.domain.LoanProductBorrowerCycleVariations org.apache.fineract.portfolio.loanproduct.domain.LoanProductConfigurableAttributes @@ -112,37 +120,35 @@ org.apache.fineract.portfolio.loanproduct.domain.LoanProductInterestRecalculationDetails org.apache.fineract.portfolio.loanproduct.domain.LoanProductPaymentAllocationRule org.apache.fineract.portfolio.loanproduct.domain.LoanProductVariableInstallmentConfig - org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationType - org.apache.fineract.portfolio.loanproduct.domain.DueType - org.apache.fineract.portfolio.loanproduct.domain.AllocationType - org.apache.fineract.portfolio.loanproduct.domain.FutureInstallmentAllocationRule org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationTransactionType - org.apache.fineract.portfolio.loanproduct.domain.AllocationTypeListConverter - org.apache.fineract.portfolio.loanaccount.domain.LoanCreditAllocationRule - org.apache.fineract.portfolio.loanproduct.domain.CreditAllocationTransactionType + org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationType org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationTypeListConverter org.apache.fineract.portfolio.loanproduct.domain.SupportedInterestRefundTypesListConverter - org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeParameter - org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecks org.apache.fineract.interoperation.domain.InteropIdentifier org.apache.fineract.portfolio.interestratechart.domain.InterestIncentives org.apache.fineract.portfolio.interestratechart.domain.InterestRateChart org.apache.fineract.portfolio.interestratechart.domain.InterestRateChartSlab + org.apache.fineract.portfolio.savings.domain.DepositAccountInterestIncentives org.apache.fineract.portfolio.savings.domain.DepositAccountInterestRateChart org.apache.fineract.portfolio.savings.domain.DepositAccountInterestRateChartSlabs - org.apache.fineract.portfolio.savings.domain.DepositAccountInterestIncentives org.apache.fineract.portfolio.savings.domain.DepositAccountOnHoldTransaction org.apache.fineract.portfolio.savings.domain.DepositAccountTermAndPreClosure + org.apache.fineract.portfolio.savings.domain.DepositProductRecurringDetail + org.apache.fineract.portfolio.savings.domain.DepositProductTermAndPreClosure + org.apache.fineract.portfolio.savings.domain.FixedDepositAccount + org.apache.fineract.portfolio.savings.domain.FixedDepositProduct org.apache.fineract.portfolio.savings.domain.GroupSavingsIndividualMonitoring - org.apache.fineract.portfolio.savings.domain.SavingsProduct + org.apache.fineract.portfolio.savings.domain.RecurringDepositAccount + org.apache.fineract.portfolio.savings.domain.RecurringDepositProduct org.apache.fineract.portfolio.savings.domain.SavingsAccount org.apache.fineract.portfolio.savings.domain.SavingsAccountCharge org.apache.fineract.portfolio.savings.domain.SavingsAccountChargePaidBy org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionTaxDetails org.apache.fineract.portfolio.savings.domain.SavingsOfficerAssignmentHistory + org.apache.fineract.portfolio.savings.domain.SavingsProduct org.apache.fineract.accounting.rule.domain.AccountingRule org.apache.fineract.accounting.rule.domain.AccountingTagRule @@ -151,10 +157,10 @@ org.apache.fineract.portfolio.charge.domain.Charge - org.apache.fineract.portfolio.tax.domain.TaxGroup - org.apache.fineract.portfolio.tax.domain.TaxGroupMappings org.apache.fineract.portfolio.tax.domain.TaxComponent org.apache.fineract.portfolio.tax.domain.TaxComponentHistory + org.apache.fineract.portfolio.tax.domain.TaxGroup + org.apache.fineract.portfolio.tax.domain.TaxGroupMappings false diff --git a/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java b/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java index aa6a210aa..5002fae69 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java +++ b/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java @@ -42,7 +42,6 @@ import org.apache.fineract.infrastructure.dataqueries.service.GenericDataService import org.apache.fineract.infrastructure.jobs.ScheduledJobRunnerConfig; import org.apache.fineract.infrastructure.jobs.service.JobRegisterService; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; @@ -103,7 +102,7 @@ public class TestConfiguration { @Primary @Bean public HikariDataSource tenantDataSource() { - HikariDataSource mockDataSource = mock(HikariDataSource.class, Mockito.RETURNS_MOCKS); + HikariDataSource mockDataSource = mock(HikariDataSource.class, RETURNS_MOCKS); return mockDataSource; } @@ -112,7 +111,7 @@ public class TestConfiguration { */ @Bean public RoutingDataSource hikariTenantDataSource() { - RoutingDataSource mockDataSource = mock(RoutingDataSource.class, Mockito.RETURNS_MOCKS); + RoutingDataSource mockDataSource = mock(RoutingDataSource.class, RETURNS_MOCKS); return mockDataSource; } @@ -128,17 +127,17 @@ public class TestConfiguration { @Primary @Bean public TenantDetailsService tenantDetailsService() { - return mock(TenantDetailsService.class, Mockito.RETURNS_MOCKS); + return mock(TenantDetailsService.class, RETURNS_MOCKS); } @Bean public ExtendedSpringLiquibaseFactory liquibaseFactory() { - return mock(ExtendedSpringLiquibaseFactory.class, Mockito.RETURNS_MOCKS); + return mock(ExtendedSpringLiquibaseFactory.class, RETURNS_MOCKS); } @Bean public DatabaseIndependentQueryService databaseIndependentQueryService() { - return mock(DatabaseIndependentQueryService.class, Mockito.RETURNS_MOCKS); + return mock(DatabaseIndependentQueryService.class, RETURNS_MOCKS); } @Bean diff --git a/fineract-war/build.gradle b/fineract-war/build.gradle index 41c79e0ff..c7a29aad0 100644 --- a/fineract-war/build.gradle +++ b/fineract-war/build.gradle @@ -23,28 +23,58 @@ apply plugin: 'distribution' apply from: "${rootDir}/buildSrc/src/main/groovy/org.apache.fineract.dependencies.gradle" war { + description = 'Assembles a WAR archive containing the web application' archiveFileName = 'fineract-provider.war' - from("$rootDir/licenses/binary/") { - // notice the parens - into "WEB-INF/licenses/binary/" // no leading slash + + // Enable caching + outputs.cacheIf { true } + + // Track inputs explicitly + inputs.files(project.configurations.runtimeClasspath) + .withPropertyName("runtimeClasspath") + .withPathSensitivity(PathSensitivity.RELATIVE) + inputs.files(project.sourceSets.main.output.classesDirs) + .withPropertyName("classes") + .withPathSensitivity(PathSensitivity.RELATIVE) + + def licensesDir = file("$rootDir/licenses/binary/") + if (licensesDir.exists()) { + inputs.dir(licensesDir) + .withPropertyName("licenses") + .withPathSensitivity(PathSensitivity.RELATIVE) + + from(licensesDir) { + into "WEB-INF/licenses/binary/" + } } - from("$rootDir/LICENSE_RELEASE") { - // notice the parens - into "WEB-INF/" // no leading slash + + def legalFiles = [ + file("$rootDir/LICENSE_RELEASE"), + file("$rootDir/NOTICE_RELEASE"), + file("$rootDir/DISCLAIMER") + ].findAll { it.exists() } + + if (!legalFiles.empty) { + inputs.files(legalFiles) + .withPropertyName("legalFiles") + .withPathSensitivity(PathSensitivity.RELATIVE) } - from("$rootDir/NOTICE_RELEASE") { - // notice the parens - into "WEB-INF/" // no leading slash + + legalFiles.each { file -> + from(file) { + into "WEB-INF/" + } } + rename ('LICENSE_RELEASE', 'LICENSE') rename ('NOTICE_RELEASE', 'NOTICE') - - from("$rootDir/DISCLAIMER") { - // notice the parens - into "WEB-INF/" // no leading slash - } + enabled = true archiveClassifier = '' + + // Ensure reproducible output + preserveFileTimestamps = false + reproducibleFileOrder = true } dependencies { @@ -64,12 +94,24 @@ dependencies { tasks.withType(Tar) { compression Compression.GZIP archiveExtension = 'tar.gz' + + // Enable caching for all tar tasks + outputs.cacheIf { true } + + // Ensure reproducible output + preserveFileTimestamps = false + reproducibleFileOrder = true } distributions { binary { distributionBaseName = 'apache-fineract-binary' contents { + // Track inputs explicitly for binary distribution + filesMatching('**/*.jar') { + it.path = it.path.replaceAll('-\\d+\\.\\d+\\.\\d+(-SNAPSHOT)?', '-' + version) + } + from ("$rootDir/fineract-client/build/libs/") { include 'fineract-client-*.jar' } @@ -99,19 +141,52 @@ distributions { src { distributionBaseName = 'apache-fineract-src' contents { - from "$rootDir/" - exclude '**/build' , '.git', '**/.gradle', '.github', '**/.settings', '**/.project', '**/.classpath', '.idea', 'out', '._.DS_Store', '.DS_Store', 'WebContent', '**/.externalToolbuilders', '.theia', '.gitpod.yml', 'LICENSE_RELEASE', 'NOTICE_RELEASE', '**/licenses', '*.class', '**/bin', '*.log', '.dockerignore', '**/.gitkeep' + // Track inputs explicitly for source distribution + from("$rootDir/") { + exclude '**/build' , '.git', '**/.gradle', '.github', '**/.settings', '**/.project', + '**/.classpath', '.idea', 'out', '._.DS_Store', '.DS_Store', 'WebContent', + '**/.externalToolbuilders', '.theia', '.gitpod.yml', 'LICENSE_RELEASE', + 'NOTICE_RELEASE', '**/licenses', '*.class', '**/bin', '*.log', '.dockerignore', + '**/.gitkeep' + + // Ensure consistent file paths for caching + eachFile { details -> + details.path = details.path.replace('\\', '/') + } + } rename ('LICENSE_SOURCE', 'LICENSE') rename ('NOTICE_SOURCE', 'NOTICE') } } +} + +// Configure specific tar tasks +tasks.named('binaryDistTar') { + description = 'Assembles the binary distribution as a tar archive' + outputs.cacheIf { true } + + // Track dependencies explicitly + dependsOn(war, ':fineract-client:jar', ':fineract-avro-schemas:jar', + ':fineract-provider:build', ':fineract-doc:doc', + ':fineract-client:javadocJar', ':fineract-client:sourcesJar', + ':fineract-avro-schemas:javadocJar', ':fineract-avro-schemas:sourcesJar') + doLast { - file("${buildDir}/distributions/apache-fineract-binary-${version}.tar.gz").renameTo("${buildDir}/distributions/apache-fineract-${version}-binary.tar.gz") - file("${buildDir}/distributions/apache-fineract-src-${version}.tar.gz").renameTo("${buildDir}/distributions/apache-fineract-${version}-src.tar.gz") + file("${buildDir}/distributions/apache-fineract-binary-${version}.tar.gz") + .renameTo("${buildDir}/distributions/apache-fineract-${version}-binary.tar.gz") } } +tasks.named('srcDistTar') { + description = 'Assembles the source distribution as a tar archive' + outputs.cacheIf { true } + + doLast { + file("${buildDir}/distributions/apache-fineract-src-${version}.tar.gz") + .renameTo("${buildDir}/distributions/apache-fineract-${version}-src.tar.gz") + } +} + +// Disable zip distributions as they're not needed binaryDistZip.enabled false srcDistZip.enabled false -// NOTE: Gradle suggested these dependencies -binaryDistTar.dependsOn(war, ':fineract-client:jar', ':fineract-avro-schemas:jar', ':fineract-provider:build', ':fineract-doc:doc') diff --git a/gradle.properties b/gradle.properties index d2b7f204f..022d5cbce 100644 --- a/gradle.properties +++ b/gradle.properties @@ -20,3 +20,7 @@ org.gradle.jvmargs=-Xmx6g --add-exports jdk.compiler/com.sun.tools.javac.api=ALL buildType=BUILD org.gradle.caching=true org.gradle.parallel=true +org.gradle.daemon.idletimeout=10800000 +# Temporarily disabled until we fix configuration cache compatibility +#org.gradle.configuration-cache=true +org.gradle.vfs.watch=true diff --git a/integration-tests/build.gradle b/integration-tests/build.gradle index c5839bf35..7ef84a2c9 100644 --- a/integration-tests/build.gradle +++ b/integration-tests/build.gradle @@ -97,6 +97,18 @@ if (!project.hasProperty('cargoDisabled')) { } } +// Configure proper test output directories +sourceSets { + test { + output.resourcesDir = layout.buildDirectory.dir('resources/test').get().asFile + java.destinationDirectory = layout.buildDirectory.dir('classes/java/test').get().asFile + } +} + +tasks.named('compileTestJava') { + outputs.cacheIf { true } +} + // NOTE: Gradle suggested these dependencies compileTestJava.dependsOn(':fineract-provider:generateGitProperties', ':fineract-provider:processResources', ':fineract-provider:resolve') spotbugsTest.dependsOn(':fineract-provider:generateGitProperties', ':fineract-provider:processResources', ':fineract-provider:resolve') diff --git a/integration-tests/dependencies.gradle b/integration-tests/dependencies.gradle index f8b4e1dbf..7d2b7bd86 100644 --- a/integration-tests/dependencies.gradle +++ b/integration-tests/dependencies.gradle @@ -33,9 +33,7 @@ dependencies { project(path: ':fineract-provider', configuration: 'runtimeElements'), project(path: ':fineract-avro-schemas', configuration: 'runtimeElements'), project(path: ':fineract-client', configuration: 'runtimeElements'), - project(path: ':fineract-progressive-loan', configuration: 'runtimeElements'), - 'com.intuit.karate:karate-junit5', - // 'com.google.code.gson:gson', + project(path: ':fineract-progressive-loan', configuration: 'runtimeElements') ) testImplementation ('org.mock-server:mockserver-junit-jupiter') { exclude group: 'com.sun.mail', module: 'mailapi' @@ -59,4 +57,5 @@ dependencies { testAnnotationProcessor 'org.mapstruct:mapstruct-processor' testImplementation 'com.github.tomakehurst:wiremock-standalone' + testImplementation 'com.google.guava:guava:32.1.3-jre' } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/SearchHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/SearchHelper.java index c0c6db7ec..bb42744c4 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/SearchHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/SearchHelper.java @@ -18,8 +18,8 @@ */ package org.apache.fineract.integrationtests.common; +import com.google.common.reflect.TypeToken; import com.google.gson.Gson; -import com.linecorp.armeria.internal.shaded.guava.reflect.TypeToken; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; import java.lang.reflect.Type; diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/accounting/AccountRuleHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/accounting/AccountRuleHelper.java index c13db44a2..f0acd3807 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/accounting/AccountRuleHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/accounting/AccountRuleHelper.java @@ -18,8 +18,8 @@ */ package org.apache.fineract.integrationtests.common.accounting; +import com.google.common.reflect.TypeToken; import com.google.gson.Gson; -import com.linecorp.armeria.internal.shaded.guava.reflect.TypeToken; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; import java.lang.reflect.Type; diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/commands/MakercheckersHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/commands/MakercheckersHelper.java index 5a36b9993..0e1039c78 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/commands/MakercheckersHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/commands/MakercheckersHelper.java @@ -18,8 +18,8 @@ */ package org.apache.fineract.integrationtests.common.commands; +import com.google.common.reflect.TypeToken; import com.google.gson.Gson; -import com.linecorp.armeria.internal.shaded.guava.reflect.TypeToken; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; import java.lang.reflect.Type; diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/products/DelinquencyBucketsHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/products/DelinquencyBucketsHelper.java index 32efd26da..cb9a91df3 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/products/DelinquencyBucketsHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/products/DelinquencyBucketsHelper.java @@ -22,8 +22,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import com.google.common.reflect.TypeToken; import com.google.gson.Gson; -import com.linecorp.armeria.internal.shaded.guava.reflect.TypeToken; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; import java.lang.reflect.Type; diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/products/DelinquencyRangesHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/products/DelinquencyRangesHelper.java index 220f0ec67..9f3f9e038 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/products/DelinquencyRangesHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/products/DelinquencyRangesHelper.java @@ -18,8 +18,8 @@ */ package org.apache.fineract.integrationtests.common.products; +import com.google.common.reflect.TypeToken; import com.google.gson.Gson; -import com.linecorp.armeria.internal.shaded.guava.reflect.TypeToken; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; import java.lang.reflect.Type;