A Gradle plugin allows targeting multiple gradleApi()s versions by
leveraging Java Plugin's Variant Features.
Apply the plugin at your java-gradle-plugin project:
plugins {
`java-gradle-plugin`
id("io.github.gmazzo.gradle.multiapi") version "<latest>"
}
gradlePlugin {
apiTargets("7.0", "8.1", "8.13")
plugins {
create("myPlugin") {
// configure your plugin here
}
}
}For each declared, a dedicated gradle<version> source will be created (with a companion gradle<version>Test test
suite)
Note
main and test source sets will act as common shared code for all variants.
Important
The plugin will automatically configure the gradleApi() and gradleTestkit() with the right target version on each
source.
Do not declare them manually (as you usually will do) since will may breck the classpath.
When kotlin plugin is applied, also gradleKotlinDsl() will be configured.
An opinionated approach will be to leverage Java's ServiceLoader mechanism to load the right implementation for each
target version.
For instance, considering Gradle's 8.13 breaking change on JvmTestSuite
where TestSuiteType was dropped in favor of new TestSuiteName, this could be addressed as the following:
In main source set:
interface GradleAPIAdapter {
fun AttributeContainer.setDefaultTestSuite(objects: ObjectFactory)
fun AggregateTestReport.setDefaultTestSuite()
fun JacocoCoverageReport.setDefaultTestSuite()
companion object : GradleAPIAdapter by ServiceLoader.load(GradleAPIAdapter::class.java).single()
}And a resource pointing to its implementation:
META-INF/services/io.github.gmazzo.android.test.aggregation.GradleAPIAdapter:
io.github.gmazzo.android.test.aggregation.GradleAPIAdapterImpl
Then in gradle8.0 source set:
import org.gradle.api.attributes.TestSuiteType.TEST_SUITE_TYPE_ATTRIBUTE
import org.gradle.api.attributes.TestSuiteType.UNIT_TEST
class GradleAPIAdapterImpl : GradleAPIAdapter {
override fun AttributeContainer.setDefaultTestSuite(objects: ObjectFactory) {
attribute(TEST_SUITE_TYPE_ATTRIBUTE, objects.named(UNIT_TEST))
}
override fun AggregateTestReport.setDefaultTestSuite() {
testType.set(UNIT_TEST)
}
override fun JacocoCoverageReport.setDefaultTestSuite() {
testType.set(UNIT_TEST)
}
}And in gradle813 source set (the version introducing the breaking change):
import org.gradle.api.attributes.TestSuiteName.TEST_SUITE_NAME_ATTRIBUTE
import org.gradle.api.tasks.SourceSet.TEST_SOURCE_SET_NAME
class GradleAPIAdapterImpl : GradleAPIAdapter {
override fun AttributeContainer.setDefaultTestSuite(objects: ObjectFactory) {
attribute(TEST_SUITE_NAME_ATTRIBUTE, objects.named(TEST_SOURCE_SET_NAME))
}
override fun AggregateTestReport.setDefaultTestSuite() {
testSuiteName.set(TEST_SOURCE_SET_NAME)
}
override fun JacocoCoverageReport.setDefaultTestSuite() {
testSuiteName.set(TEST_SOURCE_SET_NAME)
}
}Note
This is a working example on my Android Test Aggregation plugin
By default, this plugin will feed from Gradle user's home directory when looking for distributions. This allows saving build and configuration time, by reusing already downloaded distributions.
You can customize this behavior by using any of the provided APIs or passing a custom location for Gradle to cache content:
gradlePlugin {
apiTargets("7.0", "8.1", "8.13")
apiTargets.sharedCache() // default, will use `~/.gradle/` directory
apiTargets.projectCache() // will use `buildDir/multiapi/cache` directory
apiTargets.sharedCacheDir = file("myFolder") // custom location
}