diff --git a/sqldelight-gradle-plugin/build.gradle b/sqldelight-gradle-plugin/build.gradle index d342cf478a1..fb5ee040682 100644 --- a/sqldelight-gradle-plugin/build.gradle +++ b/sqldelight-gradle-plugin/build.gradle @@ -51,7 +51,7 @@ dependencies { implementation libs.schemaCrawler.sqlite implementation projects.sqliteMigrations - implementation projects.sqldelightCompiler + api projects.sqldelightCompiler // Only shade the minimum IntelliJ libs. shade libs.intellij.core // Analysis has no dependencies. diff --git a/sqldelight-gradle-plugin/src/main/kotlin/app/cash/sqldelight/gradle/SqlDelightDatabase.kt b/sqldelight-gradle-plugin/src/main/kotlin/app/cash/sqldelight/gradle/SqlDelightDatabase.kt index 147ac691109..81d809adbc9 100644 --- a/sqldelight-gradle-plugin/src/main/kotlin/app/cash/sqldelight/gradle/SqlDelightDatabase.kt +++ b/sqldelight-gradle-plugin/src/main/kotlin/app/cash/sqldelight/gradle/SqlDelightDatabase.kt @@ -33,7 +33,9 @@ abstract class SqlDelightDatabase @Inject constructor( val migrationOutputFileFormat: Property = project.objects.property(String::class.java).convention(".sql") val generateAsync: Property = project.objects.property(Boolean::class.java).convention(false) - internal val configuration = project.configurations.create("${name}DialectClasspath").apply { + val configurationName: String = "${name}DialectClasspath" + + internal val configuration = project.configurations.create(configurationName).apply { isCanBeConsumed = false isVisible = false } diff --git a/sqldelight-gradle-plugin/src/main/kotlin/app/cash/sqldelight/gradle/VerifyMigrationTask.kt b/sqldelight-gradle-plugin/src/main/kotlin/app/cash/sqldelight/gradle/VerifyMigrationTask.kt index 725d1bda2e7..53883b642a0 100644 --- a/sqldelight-gradle-plugin/src/main/kotlin/app/cash/sqldelight/gradle/VerifyMigrationTask.kt +++ b/sqldelight-gradle-plugin/src/main/kotlin/app/cash/sqldelight/gradle/VerifyMigrationTask.kt @@ -14,6 +14,7 @@ import app.cash.sqlite.migrations.findDatabaseFiles import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.FileTree import org.gradle.api.logging.Logging +import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.IgnoreEmptyDirectories @@ -29,7 +30,9 @@ import org.gradle.api.tasks.TaskAction import org.gradle.workers.WorkAction import org.gradle.workers.WorkParameters import java.io.File -import java.util.ServiceLoader +import java.sql.DriverManager +import java.util.* +import kotlin.collections.ArrayList @CacheableTask abstract class VerifyMigrationTask : SqlDelightWorkerTask() { @@ -51,6 +54,8 @@ abstract class VerifyMigrationTask : SqlDelightWorkerTask() { @Input var verifyDefinitions: Boolean = true + @get:Input abstract val driverProperties: MapProperty + /* Tasks without an output are never considered UP-TO-DATE by Gradle. Adding an output file that's created when the * task completes successfully works around the lack of an output for this task. There may be a better solution once * https://github.com/gradle/gradle/issues/14223 is resolved. */ @@ -68,6 +73,7 @@ abstract class VerifyMigrationTask : SqlDelightWorkerTask() { it.verifyMigrations.set(verifyMigrations) it.compilationUnit.set(compilationUnit) it.verifyDefinitions.set(verifyDefinitions) + it.driverProperties.set(driverProperties.get()) } workQueue.await() }.onSuccess { @@ -92,6 +98,7 @@ abstract class VerifyMigrationTask : SqlDelightWorkerTask() { val compilationUnit: Property val verifyMigrations: Property val verifyDefinitions: Property + val driverProperties: MapProperty } abstract class VerifyMigrationAction : WorkAction { @@ -113,9 +120,12 @@ abstract class VerifyMigrationTask : SqlDelightWorkerTask() { } override fun execute() { + ServiceLoader.load(DriverInitializer::class.java).firstOrNull()?.execute( + parameters.properties.get(), + parameters.driverProperties.toProperties(), + ) if (!environment.dialect.isSqlite) return parameters.workingDirectory.get().asFile.deleteRecursively() - val catalog = createCurrentDb() val databaseFiles = sourceFolders.asSequence() @@ -146,7 +156,10 @@ abstract class VerifyMigrationTask : SqlDelightWorkerTask() { return CatalogDatabase.withInitStatements(initStatements) } - private fun checkMigration(dbFile: File, currentDb: CatalogDatabase) { + private fun checkMigration( + dbFile: File, + currentDb: CatalogDatabase, + ) { val actualCatalog = createActualDb(dbFile) val databaseComparator = ObjectDifferDatabaseComparator( ignoreDefinitions = !parameters.verifyDefinitions.get(), @@ -197,5 +210,21 @@ abstract class VerifyMigrationTask : SqlDelightWorkerTask() { lastMigrationVersion = actual } } + + private fun MapProperty.toProperties(): Properties { + val connectionProperties = Properties() + get().forEach { (key, value) -> + connectionProperties[key] = value + } + return connectionProperties + } } } + +/** + * Allows consumers to configure and register (with [DriverManager]) their custom drivers prior to + * running migration verification task. + */ +interface DriverInitializer { + fun execute(properties: SqlDelightDatabaseProperties, driverProperties: Properties) +} diff --git a/sqldelight-gradle-plugin/src/test/kotlin/app/cash/sqldelight/tests/MigrationTest.kt b/sqldelight-gradle-plugin/src/test/kotlin/app/cash/sqldelight/tests/MigrationTest.kt index 6a37a9dc286..1b115ce48a4 100644 --- a/sqldelight-gradle-plugin/src/test/kotlin/app/cash/sqldelight/tests/MigrationTest.kt +++ b/sqldelight-gradle-plugin/src/test/kotlin/app/cash/sqldelight/tests/MigrationTest.kt @@ -36,6 +36,16 @@ class MigrationTest { assertThat(output.output).contains("BUILD SUCCESSFUL") } + @Test fun `driver initializer is executed`() { + val output = GradleRunner.create() + .withCommonConfiguration(File("src/test/migration-driver-initializer")) + .withArguments("clean", "verifyMainDatabaseMigration", "--stacktrace") + .build() + + assertThat(output.output).contains("DriverInitializerImpl executed!") + assertThat(output.output).contains("BUILD SUCCESSFUL") + } + @Test fun `failing migration errors properly`() { val output = GradleRunner.create() .withCommonConfiguration(File("src/test/migration-failure")) diff --git a/sqldelight-gradle-plugin/src/test/migration-driver-initializer/build.gradle b/sqldelight-gradle-plugin/src/test/migration-driver-initializer/build.gradle new file mode 100644 index 00000000000..2701875a9da --- /dev/null +++ b/sqldelight-gradle-plugin/src/test/migration-driver-initializer/build.gradle @@ -0,0 +1,21 @@ +buildscript { + apply from: "${projectDir.absolutePath}/../buildscript.gradle" +} + +apply plugin: 'org.jetbrains.kotlin.jvm' +apply plugin: 'app.cash.sqldelight' + +sqldelight { + databases { + Database { + packageName = "com.example" + verifyMigrations = true + + dependencies.add(configurationName, project(":driverInit")) + } + } +} + +dependencies { + implementation libs.junit +} diff --git a/sqldelight-gradle-plugin/src/test/migration-driver-initializer/driverInit/build.gradle b/sqldelight-gradle-plugin/src/test/migration-driver-initializer/driverInit/build.gradle new file mode 100644 index 00000000000..c8872cdb4d2 --- /dev/null +++ b/sqldelight-gradle-plugin/src/test/migration-driver-initializer/driverInit/build.gradle @@ -0,0 +1,5 @@ +apply plugin: 'org.jetbrains.kotlin.jvm' + +dependencies { + implementation libs.sqldelight +} diff --git a/sqldelight-gradle-plugin/src/test/migration-driver-initializer/driverInit/src/main/kotlin/DriverInitializerImpl.kt b/sqldelight-gradle-plugin/src/test/migration-driver-initializer/driverInit/src/main/kotlin/DriverInitializerImpl.kt new file mode 100644 index 00000000000..b94971949d1 --- /dev/null +++ b/sqldelight-gradle-plugin/src/test/migration-driver-initializer/driverInit/src/main/kotlin/DriverInitializerImpl.kt @@ -0,0 +1,9 @@ +import app.cash.sqldelight.core.SqlDelightDatabaseProperties +import app.cash.sqldelight.gradle.DriverInitializer +import java.util.Properties + +class DriverInitializerImpl : DriverInitializer { + override fun execute(properties: SqlDelightDatabaseProperties, driverProperties: Properties) { + println("DriverInitializerImpl executed!") + } +} diff --git a/sqldelight-gradle-plugin/src/test/migration-driver-initializer/driverInit/src/main/resources/META-INF/services/app.cash.sqldelight.gradle.DriverInitializer b/sqldelight-gradle-plugin/src/test/migration-driver-initializer/driverInit/src/main/resources/META-INF/services/app.cash.sqldelight.gradle.DriverInitializer new file mode 100644 index 00000000000..51b736d2cd1 --- /dev/null +++ b/sqldelight-gradle-plugin/src/test/migration-driver-initializer/driverInit/src/main/resources/META-INF/services/app.cash.sqldelight.gradle.DriverInitializer @@ -0,0 +1 @@ +DriverInitializerImpl diff --git a/sqldelight-gradle-plugin/src/test/migration-driver-initializer/settings.gradle b/sqldelight-gradle-plugin/src/test/migration-driver-initializer/settings.gradle new file mode 100644 index 00000000000..a3b6c8113b4 --- /dev/null +++ b/sqldelight-gradle-plugin/src/test/migration-driver-initializer/settings.gradle @@ -0,0 +1,5 @@ +apply from: "../settings.gradle" + +rootProject.name = 'sqldelight-migrations' + +include(":driverInit") diff --git a/sqldelight-gradle-plugin/src/test/migration-driver-initializer/src/main/sqldelight/com/sample/Test.sq b/sqldelight-gradle-plugin/src/test/migration-driver-initializer/src/main/sqldelight/com/sample/Test.sq new file mode 100644 index 00000000000..b8212596122 --- /dev/null +++ b/sqldelight-gradle-plugin/src/test/migration-driver-initializer/src/main/sqldelight/com/sample/Test.sq @@ -0,0 +1,21 @@ +CREATE TABLE test( + value TEXT NOT NULL, + value2 TEXT +); + +CREATE INDEX testIndex + ON test(value); + +CREATE TRIGGER testTrigger + AFTER DELETE ON test + BEGIN + INSERT INTO test VALUES ("1", "2"); + END; + +CREATE VIEW testView AS + SELECT * + FROM test; + +select: +SELECT * +FROM test; \ No newline at end of file diff --git a/sqldelight-gradle-plugin/src/test/migration-driver-initializer/src/main/sqldelight/migrations/1.db b/sqldelight-gradle-plugin/src/test/migration-driver-initializer/src/main/sqldelight/migrations/1.db new file mode 100644 index 00000000000..ffbf535ec6b Binary files /dev/null and b/sqldelight-gradle-plugin/src/test/migration-driver-initializer/src/main/sqldelight/migrations/1.db differ diff --git a/sqldelight-gradle-plugin/src/test/migration-driver-initializer/src/main/sqldelight/migrations/1.sqm b/sqldelight-gradle-plugin/src/test/migration-driver-initializer/src/main/sqldelight/migrations/1.sqm new file mode 100644 index 00000000000..4b34312f0bb --- /dev/null +++ b/sqldelight-gradle-plugin/src/test/migration-driver-initializer/src/main/sqldelight/migrations/1.sqm @@ -0,0 +1,13 @@ +ALTER TABLE test ADD COLUMN value2 TEXT; + +CREATE INDEX testIndex ON test(value); + +CREATE TRIGGER testTrigger +AFTER DELETE ON test +BEGIN +INSERT INTO test VALUES ("1", "2"); +END; + +CREATE VIEW testView AS +SELECT * +FROM test; diff --git a/sqldelight-gradle-plugin/src/test/settings.gradle b/sqldelight-gradle-plugin/src/test/settings.gradle index 16baf3bd01e..5b1bc928722 100644 --- a/sqldelight-gradle-plugin/src/test/settings.gradle +++ b/sqldelight-gradle-plugin/src/test/settings.gradle @@ -14,6 +14,7 @@ dependencyResolutionManagement { library("sqldelight", "app.cash.sqldelight", "gradle-plugin") .versionRef(version("sqldelightVersion", sqldelightVersion)) + plugin("sqldelight", "app.cash.sqldelight").versionRef(version("sqldelightVersion", sqldelightVersion)) } }