diff --git a/.vscode/settings.json b/.vscode/settings.json index 432bd4e..979e720 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,7 @@ "cSpell.words": [ "gradleup", "Gratatouille", + "Liquibase", "Multiplatform", "nmcp", "OSSRH", diff --git a/docs/plugin-development/configuration-cache/README.md b/docs/plugin-development/configuration-cache/README.md index 11208d1..6923e9b 100644 --- a/docs/plugin-development/configuration-cache/README.md +++ b/docs/plugin-development/configuration-cache/README.md @@ -25,6 +25,10 @@ in the main documentation: - [Auto-testing configuration Cache compatibility](https://docs.gradle.org/current/userguide/configuration_cache.html#config_cache:testing) +## Examples and Case Studies + +- [Enabling Gradle Configuration Cache Support in the Liquibase Plugin](./example-config-cache-liquibase-plugin.md) + ## FAQ ### How to fix "invocation of 'Task.project' at execution time is unsupported"? diff --git a/docs/plugin-development/configuration-cache/example-config-cache-liquibase-plugin.md b/docs/plugin-development/configuration-cache/example-config-cache-liquibase-plugin.md index a61eb44..c5a8a36 100644 --- a/docs/plugin-development/configuration-cache/example-config-cache-liquibase-plugin.md +++ b/docs/plugin-development/configuration-cache/example-config-cache-liquibase-plugin.md @@ -1,4 +1,8 @@ -# Example - Enabling Gradle Configuration Cache Support in the Liquibase Plguin +--- +title: Case Study - Enabling Gradle Configuration Cache Support in the Liquibase Plugin +description: > + This page outlines the changes made to the Liquibase Gradle plugin to add support for Gradle's Configuration Cache. +--- ## 1. Summary @@ -17,19 +21,24 @@ For the cache to work, a critical rule must be followed: **tasks must not access The previous implementation of the plugin violated this rule in several ways: * **Direct Project Access in `LiquibaseTask`:** The main task action (`@TaskAction`) directly accessed the project's `liquibase` extension to get its configuration at execution time. + ```groovy // Violation inside LiquibaseTask's execution logic: def activities = project.liquibase.activities def runList = project.liquibase.runList jvmArgs(project.liquibase.jvmArgs) ``` + * **Project Dependency in `ArgumentBuilder`:** The `ArgumentBuilder` class, used during task execution, held a reference to the `project` and used it to access project properties, the logger, and the build directory. + ```groovy // Violations inside ArgumentBuilder: project.properties.findAll { ... } commandArguments += "--output-directory=${project.buildDir}/database/docs" ``` + * **Runtime Configuration Resolution:** The task resolved its `liquibaseRuntime` classpath inside its execution logic instead of during the configuration phase. + ```groovy // Violation inside LiquibaseTask's execution logic: def classpath = project.configurations.getByName(LiquibasePlugin.LIQUIBASE_RUNTIME_CONFIGURATION) @@ -49,6 +58,7 @@ Two new classes were created to act as simple, serializable data containers: 1. **`LiquibaseInfo`**: This class is responsible for carrying project-level information that the `ArgumentBuilder` needs. * *See the new class file: [`LiquibaseInfo.groovy`]([lhttps://github.com/Nouran-11/liquibase-gradle-plugin/blob/fix-cc/src/main/groovy/org/liquibase/gradle/LiquibaseInfo.groovy$0])* + ```groovy // org/liquibase/gradle/LiquibaseInfo.groovy class LiquibaseInfo { @@ -62,7 +72,7 @@ Two new classes were created to act as simple, serializable data containers: } } ``` -2. **`ProjectInfo`**: This class holds configuration from the `liquibase { ... }` extension block. +1. **`ProjectInfo`**: This class holds configuration from the `liquibase { ... }` extension block. * *See the new class file: [`ProjectInfo.groovy`]([https://github.com/Nouran-11/liquibase-gradle-plugin/blob/fix-cc/src/main/groovy/org/liquibase/gradle/ProjectInfo.groovy$0])* ```groovy // org/liquibase/gradle/ProjectInfo.groovy @@ -77,6 +87,7 @@ Two new classes were created to act as simple, serializable data containers: } } ``` + The key feature of these classes is the static `fromProject()` factory method. This method acts as the bridge, safely extracting data at configuration time. ### Step 2: Refactor `ArgumentBuilder` to be Stateless @@ -84,19 +95,23 @@ The key feature of these classes is the static `fromProject()` factory method. T The `ArgumentBuilder` was refactored to remove its dependency on the `Project` object. Instead of holding a reference to the project, its methods now require a `LiquibaseInfo` object to be passed in. * *See the full class changes: **[`ArgumentBuilder.groovy`]([https://github.com/liquibase/liquibase-gradle-plugin/blob/master/src/main/groovy/org/liquibase/gradle/ArgumentBuilder.groovy$0])** -> **[`ArgumentBuilder.groovy`]([https://github.com/Nouran-11/liquibase-gradle-plugin/blob/fix-cc/src/main/groovy/org/liquibase/gradle/ArgumentBuilder.groovy$0])*** **Before:** + ```groovy // ArgumentBuilder.groovy def buildLiquibaseArgs(Activity activity, commandName, supportedCommandArguments) { // ... code that used internal `project` reference ... } ``` + **After:** + ```groovy // ArgumentBuilder.groovy def buildLiquibaseArgs(Activity activity, commandName, supportedCommandArguments, LiquibaseInfo liquibaseInfo) { // ... code now uses liquibaseInfo.logger, liquibaseInfo.buildDir, etc. ... } ``` + ## Step 3: Update LiquibaseTask to Use Inputs The `@TaskAction` method (`exec` and its helpers) was rewritten to read from configured input properties instead of the project. This table highlights the specific transformations that eliminate configuration cache violations at execution time: @@ -109,6 +124,7 @@ The `@TaskAction` method (`exec` and its helpers) was rewritten to read from con | Accessing Project Properties | `argumentBuilder` reads `project.properties` | `argumentBuilder` receives `liquibaseInfo` with properties | | Accessing buildDir | `argumentBuilder` reads `project.buildDir` | `argumentBuilder` receives `liquibaseInfo` with build dir | --- + ## 4. Verification: The Configuration Cache Test To provide concrete proof of these improvements, a dedicated integration test was added. This test runs a build with the configuration cache enabled, verifying that the plugin's tasks execute successfully and are correctly stored and retrieved from the cache on subsequent runs. This confirms that the refactoring was successful and the plugin is now fully compatible. @@ -119,5 +135,5 @@ See the test in action: [Configuration Cache Test]([https://github.com/Nouran-11 ## 5. Conclusion -In conclusion, this refactoring effort was centered on achieving full compatibility with Gradle's Configuration Cache. By decoupling task execution from the project model, the plugin now allows Gradle to serialize its state and entirely skip the configuration phase on subsequent runs. This unlocks the core performance promise of the configuration cache, resulting in a dramatically faster and more efficient development workflow. +In conclusion, this refactoring effort was centered on achieving full compatibility with Gradle's Configuration Cache. By decoupling task execution from the project model, the plugin now allows Gradle to serialize its state and entirely skip the configuration phase on subsequent runs. This unlocks the core performance promise of the configuration cache, resulting in a dramatically faster and more efficient development workflow. diff --git a/docs/plugin-development/reporting-api/README.md b/docs/plugin-development/reporting-api/README.md index 3ef7b14..48899e4 100644 --- a/docs/plugin-development/reporting-api/README.md +++ b/docs/plugin-development/reporting-api/README.md @@ -1,4 +1,9 @@ -# Gradle Reporting API +--- +title: Gradle Reporting API +description: > + Gradle has a reporting system that tasks creating reports can expose, + letting users configure formats and output locations. +--- Gradle has a reporting system that tasks creating reports can expose, letting users configure formats and output locations. For plugin developers that would like closer integration with Gradle systems, to integrate the [Reporting API](https://docs.gradle.org/current/javadoc/org/gradle/api/reporting/Reporting.html) diff --git a/mkdocs.yml b/mkdocs.yml index 2bd3404..3cffd1d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -37,8 +37,10 @@ nav: - Plugin Development: - Summary: plugin-development/README.md - Kotlin plugin development: plugin-development/kotlin-plugins.md - - Ensuring Configuration Cache compatibility: plugin-development/configuration-cache/ - - Gradle Reporting API: plugin-development/reporting-api/ + - Ensuring Configuration Cache compatibility: + - Overview: plugin-development/configuration-cache/ + - Case study - Liquibase Plugin: plugin-development/configuration-cache/example-config-cache-liquibase-plugin.md + - Gradle Reporting API: plugin-development/reporting-api/README.md # Theme theme: