diff --git a/buildSrc/src/main/kotlin/pg-index-health-test-starter.java-compilation.gradle.kts b/buildSrc/src/main/kotlin/pg-index-health-test-starter.java-compilation.gradle.kts new file mode 100644 index 0000000..b33ae74 --- /dev/null +++ b/buildSrc/src/main/kotlin/pg-index-health-test-starter.java-compilation.gradle.kts @@ -0,0 +1,79 @@ +plugins { + id("java") + id("jacoco") +} + +val versionCatalog = extensions.getByType().named("libs") + +dependencies { + versionCatalog.findLibrary("junit-bom").ifPresent { + testImplementation(platform(it)) + } +} + +java { + // Don't forget about Kotlin app + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + +tasks { + withType().configureEach { + options.compilerArgs.add("-parameters") + } + + test { + useJUnitPlatform() + finalizedBy(jacocoTestReport, jacocoTestCoverageVerification) + } + + jacocoTestReport { + dependsOn(test) + reports { + xml.required.set(true) + html.required.set(true) + } + } + + jacocoTestCoverageVerification { + dependsOn(jacocoTestReport) + violationRules { + rule { + limit { + counter = "CLASS" + value = "MISSEDCOUNT" + maximum = "0.0".toBigDecimal() + } + } + rule { + limit { + counter = "METHOD" + value = "MISSEDCOUNT" + maximum = "0.0".toBigDecimal() + } + } + rule { + limit { + counter = "LINE" + value = "MISSEDCOUNT" + maximum = "0.0".toBigDecimal() + } + } + rule { + limit { + counter = "INSTRUCTION" + value = "COVEREDRATIO" + minimum = "1.0".toBigDecimal() + } + } + } + } + + check { + dependsOn(jacocoTestCoverageVerification) + } +} + +jacoco { + toolVersion = "0.8.12" +} diff --git a/buildSrc/src/main/kotlin/pg-index-health-test-starter.java-conventions.gradle.kts b/buildSrc/src/main/kotlin/pg-index-health-test-starter.java-conventions.gradle.kts index 3c10bfd..9ede81c 100644 --- a/buildSrc/src/main/kotlin/pg-index-health-test-starter.java-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/pg-index-health-test-starter.java-conventions.gradle.kts @@ -14,16 +14,10 @@ plugins { id("net.ltgt.errorprone") } -val versionCatalog = extensions.getByType().named("libs") - dependencies { - versionCatalog.findLibrary("junit-bom").ifPresent { - testImplementation(platform(it)) - } - checkstyle("com.thomasjensen.checkstyle.addons:checkstyle-addons:7.0.1") - errorprone("com.google.errorprone:error_prone_core:2.26.1") + errorprone("com.google.errorprone:error_prone_core:2.27.0") errorprone("jp.skypencil.errorprone.slf4j:errorprone-slf4j:0.1.23") spotbugsPlugins("jp.skypencil.findbugs.slf4j:bug-pattern:1.5.0") @@ -31,12 +25,7 @@ dependencies { spotbugsPlugins("com.mebigfatguy.sb-contrib:sb-contrib:7.6.4") } -java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 -} tasks.withType().configureEach { - options.compilerArgs.add("-parameters") options.errorprone { disableWarningsInGeneratedCode.set(true) disable("Slf4jLoggerShouldBeNonStatic") @@ -45,9 +34,7 @@ tasks.withType().configureEach { tasks { test { - useJUnitPlatform() dependsOn(checkstyleMain, checkstyleTest, pmdMain, pmdTest, spotbugsMain, spotbugsTest) - finalizedBy(jacocoTestReport, jacocoTestCoverageVerification) } jar { @@ -65,61 +52,11 @@ tasks { } } - jacocoTestReport { - dependsOn(test) - reports { - xml.required.set(true) - html.required.set(true) - } - } - - jacocoTestCoverageVerification { - dependsOn(jacocoTestReport) - violationRules { - rule { - limit { - counter = "CLASS" - value = "MISSEDCOUNT" - maximum = "0.0".toBigDecimal() - } - } - rule { - limit { - counter = "METHOD" - value = "MISSEDCOUNT" - maximum = "0.0".toBigDecimal() - } - } - rule { - limit { - counter = "LINE" - value = "MISSEDCOUNT" - maximum = "0.0".toBigDecimal() - } - } - rule { - limit { - counter = "INSTRUCTION" - value = "COVEREDRATIO" - minimum = "1.0".toBigDecimal() - } - } - } - } - - check { - dependsOn(jacocoTestCoverageVerification) - } - withType().configureEach { dependsOn(test, jacocoTestReport) } } -jacoco { - toolVersion = "0.8.12" -} - checkstyle { toolVersion = "10.15.0" configFile = file("../config/checkstyle/checkstyle.xml") @@ -129,7 +66,7 @@ checkstyle { } pmd { - toolVersion = "7.0.0" + toolVersion = "7.1.0" isConsoleOutput = true ruleSetFiles = files("../config/pmd/pmd.xml") ruleSets = listOf() diff --git a/buildSrc/src/test/kotlin/io/github/mfvanek/pg/spring/JavaConventionPluginTest.kt b/buildSrc/src/test/kotlin/io/github/mfvanek/pg/spring/JavaConventionPluginTest.kt index 6721bef..d7077a3 100644 --- a/buildSrc/src/test/kotlin/io/github/mfvanek/pg/spring/JavaConventionPluginTest.kt +++ b/buildSrc/src/test/kotlin/io/github/mfvanek/pg/spring/JavaConventionPluginTest.kt @@ -13,6 +13,7 @@ internal class JavaConventionPluginTest : PluginTestBase() { fun init() { buildFile.appendText(""" |plugins { + | id("pg-index-health-test-starter.java-compilation") | id("pg-index-health-test-starter.java-conventions") |} | diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml new file mode 100644 index 0000000..cbb6f0b --- /dev/null +++ b/config/detekt/detekt.yml @@ -0,0 +1,15 @@ +performance: + SpreadOperator: + active: false + +libraries: + LibraryEntitiesShouldNotBePublic: + active: false + +formatting: + MaximumLineLength: + maxLineLength: 200 + +style: + MaxLineLength: + maxLineLength: 200 diff --git a/console-demo-app/build.gradle.kts b/console-demo-app/build.gradle.kts index 1717677..1a54979 100644 --- a/console-demo-app/build.gradle.kts +++ b/console-demo-app/build.gradle.kts @@ -1,4 +1,5 @@ plugins { + id("pg-index-health-test-starter.java-compilation") id("pg-index-health-test-starter.java-conventions") alias(libs.plugins.spring.boot.gradlePlugin) alias(libs.plugins.spring.dependency.management) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 79e7bdf..34806c3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,6 +4,7 @@ pitest-junit5Plugin = "1.2.1" pitest-core = "1.15.3" pg-index-health = "0.10.3" commons-lang3 = "3.14.0" +detekt = "1.23.6" [libraries] junit-bom = "org.junit:junit-bom:5.10.2" @@ -21,7 +22,11 @@ pg-index-health-core = { group = "io.github.mfvanek", name = "pg-index-health", pg-index-health-jdbcConnection = { group = "io.github.mfvanek", name = "pg-index-health-jdbc-connection", version.ref = "pg-index-health" } pg-index-health-generator = { group = "io.github.mfvanek", name = "pg-index-health-generator", version.ref = "pg-index-health" } pg-index-health-testing = { group = "io.github.mfvanek", name = "pg-index-health-testing", version.ref = "pg-index-health" } +testcontainers-bom = { group = "org.testcontainers", name = "testcontainers-bom", version = "1.19.7" } +detekt-formatting = { group = "io.gitlab.arturbosch.detekt", name = "detekt-formatting", version.ref = "detekt" } +detekt-libraries = { group = "io.gitlab.arturbosch.detekt", name = "detekt-rules-libraries", version.ref = "detekt" } [plugins] spring-boot-gradlePlugin = { id = "org.springframework.boot", version.ref = "spring-boot" } spring-dependency-management = { id = "io.spring.dependency-management", version = "1.1.4" } +detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } diff --git a/h2-demo-app/build.gradle.kts b/h2-demo-app/build.gradle.kts index c6ef81a..2a3feb9 100644 --- a/h2-demo-app/build.gradle.kts +++ b/h2-demo-app/build.gradle.kts @@ -1,4 +1,5 @@ plugins { + id("pg-index-health-test-starter.java-compilation") id("pg-index-health-test-starter.java-conventions") alias(libs.plugins.spring.boot.gradlePlugin) alias(libs.plugins.spring.dependency.management) diff --git a/kotlin-demo-app/build.gradle.kts b/kotlin-demo-app/build.gradle.kts new file mode 100644 index 0000000..35e75f9 --- /dev/null +++ b/kotlin-demo-app/build.gradle.kts @@ -0,0 +1,50 @@ +import io.gitlab.arturbosch.detekt.Detekt +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("jvm") version "1.9.23" + kotlin("plugin.spring") version "1.9.23" + id("pg-index-health-test-starter.java-compilation") + alias(libs.plugins.spring.boot.gradlePlugin) + alias(libs.plugins.spring.dependency.management) + alias(libs.plugins.detekt) +} + +ext["commons-lang3.version"] = libs.versions.commons.lang3.get() + +dependencies { + implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation(project(":pg-index-health-test-starter")) + implementation(libs.spring.boot.starter.data.jdbc) + implementation(libs.pg.index.health.testing) + implementation(platform(libs.testcontainers.bom)) + implementation("org.testcontainers:postgresql") + + runtimeOnly(libs.database.postgresql) + + testImplementation(libs.spring.boot.starter.test) + testImplementation(libs.assertj.core) + + detektPlugins(libs.detekt.formatting) + detektPlugins(libs.detekt.libraries) +} + +tasks.withType { + kotlinOptions { + freeCompilerArgs += "-Xjsr305=strict" + jvmTarget = "11" + } +} + +detekt { + toolVersion = libs.versions.detekt.get() + config.setFrom(file("../config/detekt/detekt.yml")) + buildUponDefaultConfig = true +} + +tasks.withType().configureEach { + reports { + xml.required.set(true) + html.required.set(true) + } +} diff --git a/kotlin-demo-app/src/main/kotlin/io/github/mfvanek/pg/spring/postgres/kt/PostgresDemoApplication.kt b/kotlin-demo-app/src/main/kotlin/io/github/mfvanek/pg/spring/postgres/kt/PostgresDemoApplication.kt new file mode 100644 index 0000000..7d71e69 --- /dev/null +++ b/kotlin-demo-app/src/main/kotlin/io/github/mfvanek/pg/spring/postgres/kt/PostgresDemoApplication.kt @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2021-2024. Ivan Vakhrushev. + * https://github.com/mfvanek/pg-index-health-test-starter + * + * This file is a part of "pg-index-health-test-starter". + * + * Licensed under the Apache License 2.0 + */ + +package io.github.mfvanek.pg.spring.postgres.kt + +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.runApplication + +@SpringBootApplication +class PostgresDemoApplication + +fun main(args: Array) { + runApplication(*args) +} diff --git a/kotlin-demo-app/src/main/kotlin/io/github/mfvanek/pg/spring/postgres/kt/config/ConfigurableEnvironmentMutator.kt b/kotlin-demo-app/src/main/kotlin/io/github/mfvanek/pg/spring/postgres/kt/config/ConfigurableEnvironmentMutator.kt new file mode 100644 index 0000000..ef6066e --- /dev/null +++ b/kotlin-demo-app/src/main/kotlin/io/github/mfvanek/pg/spring/postgres/kt/config/ConfigurableEnvironmentMutator.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2021-2024. Ivan Vakhrushev. + * https://github.com/mfvanek/pg-index-health-test-starter + * + * This file is a part of "pg-index-health-test-starter". + * + * Licensed under the Apache License 2.0 + */ + +package io.github.mfvanek.pg.spring.postgres.kt.config + +import org.springframework.core.env.ConfigurableEnvironment +import org.springframework.core.env.Environment +import org.springframework.core.env.MapPropertySource +import org.testcontainers.containers.JdbcDatabaseContainer + +internal const val DATASOURCE_URL_PROP_NAME: String = "spring.datasource.url" + +internal fun addDatasourceUrlIfNeed(jdbcDatabaseContainer: JdbcDatabaseContainer<*>, environment: Environment): Boolean { + if (environment.getProperty(DATASOURCE_URL_PROP_NAME) == null && environment is ConfigurableEnvironment) { + val mps = environment.propertySources + mps.addFirst( + MapPropertySource( + "connectionString", + mapOf(DATASOURCE_URL_PROP_NAME to jdbcDatabaseContainer.jdbcUrl) + ) + ) + return true + } + return false +} diff --git a/kotlin-demo-app/src/main/kotlin/io/github/mfvanek/pg/spring/postgres/kt/config/DatabaseConfig.kt b/kotlin-demo-app/src/main/kotlin/io/github/mfvanek/pg/spring/postgres/kt/config/DatabaseConfig.kt new file mode 100644 index 0000000..fee69fe --- /dev/null +++ b/kotlin-demo-app/src/main/kotlin/io/github/mfvanek/pg/spring/postgres/kt/config/DatabaseConfig.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021-2024. Ivan Vakhrushev. + * https://github.com/mfvanek/pg-index-health-test-starter + * + * This file is a part of "pg-index-health-test-starter". + * + * Licensed under the Apache License 2.0 + */ + +package io.github.mfvanek.pg.spring.postgres.kt.config + +import com.zaxxer.hikari.HikariConfig +import com.zaxxer.hikari.HikariDataSource +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.core.env.Environment +import org.testcontainers.containers.JdbcDatabaseContainer +import org.testcontainers.containers.PostgreSQLContainer +import org.testcontainers.containers.wait.strategy.Wait +import javax.sql.DataSource + +@Configuration(proxyBeanMethods = false) +class DatabaseConfig { + @Bean(initMethod = "start", destroyMethod = "stop") + fun jdbcDatabaseContainer(): JdbcDatabaseContainer<*> { + return PostgreSQLContainer("postgres:16.2") + .withDatabaseName("demo_for_pg_index_health_starter") + .withUsername("demo_user") + .withPassword("myUniquePassword") + .waitingFor(Wait.forListeningPort()) + } + + @Bean + fun dataSource(jdbcDatabaseContainer: JdbcDatabaseContainer<*>, environment: Environment): DataSource { + addDatasourceUrlIfNeed(jdbcDatabaseContainer, environment) + val hikariConfig = HikariConfig() + hikariConfig.jdbcUrl = jdbcDatabaseContainer.jdbcUrl + hikariConfig.username = jdbcDatabaseContainer.username + hikariConfig.password = jdbcDatabaseContainer.password + return HikariDataSource(hikariConfig) + } +} diff --git a/kotlin-demo-app/src/main/resources/application.yaml b/kotlin-demo-app/src/main/resources/application.yaml new file mode 100644 index 0000000..418fe12 --- /dev/null +++ b/kotlin-demo-app/src/main/resources/application.yaml @@ -0,0 +1,5 @@ +debug: false + +spring: + main: + banner-mode: off diff --git a/kotlin-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/PostgresDemoApplicationKtTest.kt b/kotlin-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/PostgresDemoApplicationKtTest.kt new file mode 100644 index 0000000..f53b23e --- /dev/null +++ b/kotlin-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/PostgresDemoApplicationKtTest.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021-2024. Ivan Vakhrushev. + * https://github.com/mfvanek/pg-index-health-test-starter + * + * This file is a part of "pg-index-health-test-starter". + * + * Licensed under the Apache License 2.0 + */ + +package io.github.mfvanek.pg.spring.postgres.kt + +import com.zaxxer.hikari.HikariDataSource +import io.github.mfvanek.pg.connection.PgConnection +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.context.ApplicationContext +import org.springframework.core.env.Environment +import org.springframework.test.context.ActiveProfiles + +@ActiveProfiles("test") +@SpringBootTest +class PostgresDemoApplicationKtTest { + + @Autowired + private lateinit var applicationContext: ApplicationContext + + @Autowired + private lateinit var environment: Environment + + @Test + fun contextLoadsAndDoesNotContainPgIndexHealthBeans() { + assertThat(applicationContext.getBean("dataSource")) + .isInstanceOf(HikariDataSource::class.java) + + assertThat(applicationContext.getBean("pgConnection")) + .isInstanceOf(PgConnection::class.java) + + assertThat(environment.getProperty("spring.datasource.url")) + .isNotBlank() + .startsWith("jdbc:postgresql://localhost:") + .endsWith("/demo_for_pg_index_health_starter?loggerLevel=OFF") + } +} diff --git a/kotlin-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/PostgresDemoApplicationRunKtTest.kt b/kotlin-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/PostgresDemoApplicationRunKtTest.kt new file mode 100644 index 0000000..6345cb8 --- /dev/null +++ b/kotlin-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/PostgresDemoApplicationRunKtTest.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2021-2024. Ivan Vakhrushev. + * https://github.com/mfvanek/pg-index-health-test-starter + * + * This file is a part of "pg-index-health-test-starter". + * + * Licensed under the Apache License 2.0 + */ + +package io.github.mfvanek.pg.spring.postgres.kt + +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatCode +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.springframework.boot.test.system.CapturedOutput +import org.springframework.boot.test.system.OutputCaptureExtension + +@ExtendWith(OutputCaptureExtension::class) +class PostgresDemoApplicationRunKtTest { + + @Test + fun applicationShouldRun(output: CapturedOutput) { + assertThatCode { main(arrayOf()) } + .doesNotThrowAnyException() + assertThat(output.all) + .contains("Starting PostgresDemoApplicationKt using Java") + .contains("Container is started (JDBC URL: jdbc:postgresql://localhost:") + .contains("Started PostgresDemoApplicationKt in") + } +} diff --git a/kotlin-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/config/ConfigurableEnvironmentMutatorKtTest.kt b/kotlin-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/config/ConfigurableEnvironmentMutatorKtTest.kt new file mode 100644 index 0000000..3da858a --- /dev/null +++ b/kotlin-demo-app/src/test/kotlin/io/github/mfvanek/pg/spring/postgres/kt/config/ConfigurableEnvironmentMutatorKtTest.kt @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021-2024. Ivan Vakhrushev. + * https://github.com/mfvanek/pg-index-health-test-starter + * + * This file is a part of "pg-index-health-test-starter". + * + * Licensed under the Apache License 2.0 + */ + +package io.github.mfvanek.pg.spring.postgres.kt.config + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.mockito.Mockito +import org.springframework.core.env.Environment +import org.springframework.mock.env.MockEnvironment +import org.testcontainers.containers.JdbcDatabaseContainer + +class ConfigurableEnvironmentMutatorKtTest { + + private val jdbcDatabaseContainer: JdbcDatabaseContainer<*> = Mockito.mock(JdbcDatabaseContainer::class.java) + + @Test + fun shouldNotAddPropIfExist() { + val environment = MockEnvironment() + environment.setProperty(DATASOURCE_URL_PROP_NAME, "url") + + assertThat(addDatasourceUrlIfNeed(jdbcDatabaseContainer, environment)) + .isFalse() + assertThat(environment.getProperty(DATASOURCE_URL_PROP_NAME)).isEqualTo("url") + } + + @Test + fun shouldNotAddPropIfInvalidType() { + val environment = Mockito.mock(Environment::class.java) + Mockito.`when`(environment.getProperty(Mockito.anyString())).thenReturn(null) + + assertThat(addDatasourceUrlIfNeed(jdbcDatabaseContainer, environment)) + .isFalse() + } + + @Test + fun shouldAddProperty() { + val environment = MockEnvironment() + Mockito.`when`(jdbcDatabaseContainer.jdbcUrl).thenReturn("added_url") + + assertThat(addDatasourceUrlIfNeed(jdbcDatabaseContainer, environment)) + .isTrue() + assertThat(environment.getProperty(DATASOURCE_URL_PROP_NAME)).isEqualTo("added_url") + } +} diff --git a/pg-index-health-test-starter/build.gradle.kts b/pg-index-health-test-starter/build.gradle.kts index 82956b0..7cd8c90 100644 --- a/pg-index-health-test-starter/build.gradle.kts +++ b/pg-index-health-test-starter/build.gradle.kts @@ -3,6 +3,7 @@ import info.solidsoft.gradle.pitest.PitestTask description = "Spring Boot Starter for pg-index-health library" plugins { + id("pg-index-health-test-starter.java-compilation") id("pg-index-health-test-starter.java-conventions") id("java-library") id("maven-publish") diff --git a/postgres-demo-app/build.gradle.kts b/postgres-demo-app/build.gradle.kts index 7c47fb9..ea86202 100644 --- a/postgres-demo-app/build.gradle.kts +++ b/postgres-demo-app/build.gradle.kts @@ -1,4 +1,5 @@ plugins { + id("pg-index-health-test-starter.java-compilation") id("pg-index-health-test-starter.java-conventions") alias(libs.plugins.spring.boot.gradlePlugin) alias(libs.plugins.spring.dependency.management) @@ -12,7 +13,7 @@ dependencies { implementation("com.google.code.findbugs:jsr305:3.0.2") implementation(libs.spring.boot.starter.data.jdbc) implementation(libs.pg.index.health.testing) - implementation(platform("org.testcontainers:testcontainers-bom:1.19.7")) + implementation(platform(libs.testcontainers.bom)) implementation("org.testcontainers:postgresql") runtimeOnly(libs.database.postgresql) diff --git a/postgres-demo-app/src/main/java/io/github/mfvanek/pg/spring/postgres/PostgresDemoApplication.java b/postgres-demo-app/src/main/java/io/github/mfvanek/pg/spring/postgres/PostgresDemoApplication.java index fd11e9c..5556103 100644 --- a/postgres-demo-app/src/main/java/io/github/mfvanek/pg/spring/postgres/PostgresDemoApplication.java +++ b/postgres-demo-app/src/main/java/io/github/mfvanek/pg/spring/postgres/PostgresDemoApplication.java @@ -16,7 +16,7 @@ public class PostgresDemoApplication { /** - * Demo application with H2 datasource and without PostgreSQL. + * Demo application with PostgreSQL datasource. */ public static void main(final String[] args) { SpringApplication.run(PostgresDemoApplication.class, args); diff --git a/settings.gradle.kts b/settings.gradle.kts index bbe3670..b86bf47 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,3 +5,4 @@ include("h2-demo-app") include("console-demo-app") include("postgres-demo-app") include("pg-index-health-bom") +include("kotlin-demo-app")