Add plugin variants

Change configuration adding Gradle plugin variants. 'main' SourceSet
is used for minimal supported Gradle versions, 'common' SourceSet for
common code that is similar between versions, plus, currently,
'gradle70' SourceSet for Gradle 7.0+ versions.

^KT-49227 In Progress
This commit is contained in:
Yahor Berdnikau
2022-03-24 10:56:36 +01:00
parent 96b71e83ec
commit ad9aa8d519
5 changed files with 339 additions and 14 deletions
+2 -1
View File
@@ -328,7 +328,8 @@ extra["compilerArtifactsForIde"] = listOf(
// TODO: fix remaining warnings and remove this property.
extra["tasksWithWarnings"] = listOf(
":kotlin-gradle-plugin:compileKotlin"
":kotlin-gradle-plugin:compileKotlin",
":kotlin-gradle-plugin:compileGradle70Kotlin"
)
val tasksWithWarnings: List<String> by extra
+310 -9
View File
@@ -3,22 +3,48 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
import org.gradle.api.Action
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ModuleDependency
import org.gradle.api.artifacts.type.ArtifactTypeDefinition
import org.gradle.api.attributes.Attribute
import org.gradle.api.attributes.LibraryElements
import org.gradle.api.attributes.java.TargetJvmEnvironment
import org.gradle.api.attributes.plugin.GradlePluginApiVersion
import org.gradle.api.plugins.JavaLibraryPlugin
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.SourceSet
import org.gradle.jvm.tasks.Jar
import org.gradle.kotlin.dsl.*
import org.gradle.plugin.devel.plugins.JavaGradlePluginPlugin
import org.jetbrains.dokka.DokkaVersion
import org.jetbrains.dokka.gradle.DokkaTask
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.project.model.KotlinPlatformTypeAttribute
import plugins.configureDefaultPublishing
import plugins.configureKotlinPomAttributes
/**
* Gradle plugins common variants.
*
* [minimalSupportedGradleVersion] - minimal Gradle version that is supported in this variant
* [gradleApiVersion] - Gradle API dependency version. Usually should be the same as [minimalSupportedGradleVersion].
*/
enum class GradlePluginVariant(
val sourceSetName: String,
val minimalSupportedGradleVersion: String,
val gradleApiVersion: String
) {
GRADLE_MIN("main", "6.7", "6.9"),
GRADLE_70("gradle70", "7.0", "7.0"),
//GRADLE_71("gradle71", "7.1", "7.1"),
}
/**
* Configures common pom configuration parameters
*/
@@ -62,10 +88,148 @@ fun Project.excludeGradleCommonDependencies(sourceSet: SourceSet) {
}
/**
* 'main' sources are used for Gradle 6.1-6.9 versions.
* Directories are renamed into 'src/gradle61'.
* Common sources for all variants.
* Should contain classes that are independent of Gradle API version or using minimal supported Gradle api.
*/
fun Project.configureGradlePluginCommonSettings() {
fun Project.createGradleCommonSourceSet(): SourceSet {
val commonSourceSet = sourceSets.create("common") {
excludeGradleCommonDependencies(this)
dependencies {
compileOnlyConfigurationName(kotlinStdlib())
compileOnlyConfigurationName("dev.gradleplugins:gradle-api:7.2")
if (this@createGradleCommonSourceSet.name != "kotlin-gradle-plugin-api" &&
this@createGradleCommonSourceSet.name != "android-test-fixes"
) {
compileOnlyConfigurationName(project(":kotlin-gradle-plugin-api")) {
capabilities {
requireCapability("org.jetbrains.kotlin:kotlin-gradle-plugin-api-common")
}
}
}
}
}
plugins.withType<JavaLibraryPlugin>().configureEach {
this@createGradleCommonSourceSet.extensions.configure<JavaPluginExtension> {
registerFeature(commonSourceSet.name) {
usingSourceSet(commonSourceSet)
disablePublication()
}
}
}
return commonSourceSet
}
/**
* Fixes wired SourceSet does not expose compiled common classes and common resources as secondary variant
* which is used in the Kotlin Project compilation.
*/
private fun Project.fixWiredSourceSetSecondaryVariants(
wireSourceSet: SourceSet,
commonSourceSet: SourceSet
) {
configurations
.matching {
it.name == wireSourceSet.apiElementsConfigurationName ||
it.name == wireSourceSet.runtimeElementsConfigurationName
}
.configureEach {
outgoing {
variants.maybeCreate("classes").apply {
attributes {
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.CLASSES))
}
(commonSourceSet.output.classesDirs.files + wireSourceSet.output.classesDirs.files)
.toSet()
.forEach {
if (!artifacts.files.contains(it)) {
artifact(it) {
type = ArtifactTypeDefinition.JVM_CLASS_DIRECTORY
}
}
}
}
}
}
configurations
.matching { it.name == wireSourceSet.runtimeElementsConfigurationName }
.configureEach {
outgoing {
val resourcesDirectories = listOfNotNull(
commonSourceSet.output.resourcesDir,
wireSourceSet.output.resourcesDir
)
if (resourcesDirectories.isNotEmpty()) {
variants.maybeCreate("resources").apply {
attributes {
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.RESOURCES))
}
resourcesDirectories.forEach {
if (!artifacts.files.contains(it)) {
artifact(it) {
type = ArtifactTypeDefinition.JVM_RESOURCES_DIRECTORY
}
}
}
}
}
}
}
}
/**
* Make [wireSourceSet] to extend [commonSourceSet].
*/
fun Project.wireGradleVariantToCommonGradleVariant(
wireSourceSet: SourceSet,
commonSourceSet: SourceSet
) {
wireSourceSet.compileClasspath += commonSourceSet.output
wireSourceSet.runtimeClasspath += commonSourceSet.output
@Suppress("deprecation") // Needs support from KGP
wireSourceSet.withConvention(KotlinSourceSet::class) {
val wireKotlinSourceSet = this
commonSourceSet.withConvention(KotlinSourceSet::class) {
wireKotlinSourceSet.dependsOn(this)
}
}
configurations[wireSourceSet.apiConfigurationName].extendsFrom(
configurations[commonSourceSet.apiConfigurationName]
)
configurations[wireSourceSet.implementationConfigurationName].extendsFrom(
configurations[commonSourceSet.implementationConfigurationName]
)
configurations[wireSourceSet.runtimeOnlyConfigurationName].extendsFrom(
configurations[commonSourceSet.runtimeOnlyConfigurationName]
)
configurations[wireSourceSet.compileOnlyConfigurationName].extendsFrom(
configurations[commonSourceSet.compileOnlyConfigurationName]
)
fixWiredSourceSetSecondaryVariants(wireSourceSet, commonSourceSet)
tasks.withType<Jar>().configureEach {
if (name == wireSourceSet.jarTaskName) {
from(wireSourceSet.output, commonSourceSet.output)
setupPublicJar(archiveBaseName.get())
addEmbeddedRuntime()
} else if (name == wireSourceSet.sourcesJarTaskName) {
from(wireSourceSet.allSource, commonSourceSet.allSource)
}
}
}
/**
* 'main' sources are used for minimal supported Gradle versions (6.7) up to Gradle 7.0.
*/
fun Project.reconfigureMainSourcesSetForGradlePlugin(
commonSourceSet: SourceSet
) {
sourceSets.named(SourceSet.MAIN_SOURCE_SET_NAME) {
plugins.withType<JavaGradlePluginPlugin>().configureEach {
// Removing Gradle api default dependency added by 'java-gradle-plugin'
@@ -76,15 +240,16 @@ fun Project.configureGradlePluginCommonSettings() {
"compileOnly"(kotlinStdlib())
// Decoupling gradle-api artifact from current project Gradle version. Later would be useful for
// gradle plugin variants
"compileOnly"("dev.gradleplugins:gradle-api:7.2")
if (this@configureGradlePluginCommonSettings.name != "kotlin-gradle-plugin-api" &&
this@configureGradlePluginCommonSettings.name != "android-test-fixes"
"compileOnly"("dev.gradleplugins:gradle-api:${GradlePluginVariant.GRADLE_MIN.gradleApiVersion}")
if (this@reconfigureMainSourcesSetForGradlePlugin.name != "kotlin-gradle-plugin-api" &&
this@reconfigureMainSourcesSetForGradlePlugin.name != "android-test-fixes"
) {
"api"(project(":kotlin-gradle-plugin-api"))
}
}
excludeGradleCommonDependencies(this)
wireGradleVariantToCommonGradleVariant(this, commonSourceSet)
tasks.withType<Jar>().configureEach {
if (name == jarTaskName) {
@@ -96,7 +261,7 @@ fun Project.configureGradlePluginCommonSettings() {
}
plugins.withType<JavaLibraryPlugin>().configureEach {
this@configureGradlePluginCommonSettings
this@reconfigureMainSourcesSetForGradlePlugin
.extensions
.configure<JavaPluginExtension> {
withSourcesJar()
@@ -111,7 +276,17 @@ fun Project.configureGradlePluginCommonSettings() {
}
plugins.withId("org.jetbrains.dokka") {
val dokkaTask = tasks.named<DokkaTask>("dokkaJavadoc")
val dokkaTask = tasks.named<DokkaTask>("dokkaJavadoc") {
dokkaSourceSets {
named(commonSourceSet.name) {
suppress.set(false)
}
named("main") {
dependsOn(commonSourceSet)
}
}
}
tasks.withType<Jar>().configureEach {
if (name == javadocJarTaskName) {
@@ -122,6 +297,130 @@ fun Project.configureGradlePluginCommonSettings() {
}
}
/**
* Adding plugin variants: https://docs.gradle.org/current/userguide/implementing_gradle_plugins.html#plugin-with-variants
*/
fun Project.createGradlePluginVariant(
variant: GradlePluginVariant,
commonSourceSet: SourceSet,
isGradlePlugin: Boolean = true
): SourceSet {
val variantSourceSet = sourceSets.create(variant.sourceSetName) {
excludeGradleCommonDependencies(this)
wireGradleVariantToCommonGradleVariant(this, commonSourceSet)
}
plugins.withType<JavaLibraryPlugin>().configureEach {
extensions.configure<JavaPluginExtension> {
registerFeature(variantSourceSet.name) {
usingSourceSet(variantSourceSet)
if (isGradlePlugin) {
capability(project.group.toString(), project.name, project.version.toString())
}
// Enabling publishing docs jars only on CI build
// Currently dokka task runs non-incrementally and takes big amount of time
if (kotlinBuildProperties.publishGradlePluginsJavadoc ||
kotlinBuildProperties.isTeamcityBuild
) {
withJavadocJar()
}
withSourcesJar()
}
configurations.named(variantSourceSet.apiElementsConfigurationName, commonVariantAttributes())
configurations.named(variantSourceSet.runtimeElementsConfigurationName, commonVariantAttributes())
}
tasks.named<Jar>(variantSourceSet.sourcesJarTaskName) {
addEmbeddedSources()
}
}
// Enabling publishing docs jars only on CI build
// Currently dokka task runs non-incrementally and takes big amount of time
if (kotlinBuildProperties.publishGradlePluginsJavadoc ||
kotlinBuildProperties.isTeamcityBuild
) {
plugins.withId("org.jetbrains.dokka") {
val dokkaTask = tasks.register<DokkaTask>("dokka${variantSourceSet.javadocTaskName.capitalize()}") {
description = "Generates documentation in 'javadoc' format for '${variantSourceSet.javadocTaskName}' variant"
plugins.dependencies.add(
project.dependencies.create("org.jetbrains.dokka:javadoc-plugin:${DokkaVersion.version}")
)
dokkaSourceSets {
named(commonSourceSet.name) {
suppress.set(false)
}
named(variantSourceSet.name) {
dependsOn(commonSourceSet)
suppress.set(false)
}
}
}
tasks.named<Jar>(variantSourceSet.javadocJarTaskName) {
from(dokkaTask.flatMap { it.outputDirectory })
}
}
}
plugins.withId("java-gradle-plugin") {
tasks.named<Copy>(variantSourceSet.processResourcesTaskName) {
val copyPluginDescriptors = rootSpec.addChild()
copyPluginDescriptors.into("META-INF/gradle-plugins")
copyPluginDescriptors.from(tasks.named("pluginDescriptors"))
}
}
configurations.configureEach {
if (isCanBeConsumed && this@configureEach.name.startsWith(variantSourceSet.name)) {
attributes {
attribute(
GradlePluginApiVersion.GRADLE_PLUGIN_API_VERSION_ATTRIBUTE,
objects.named(variant.minimalSupportedGradleVersion)
)
}
}
}
dependencies {
variantSourceSet.compileOnlyConfigurationName(kotlinStdlib())
variantSourceSet.compileOnlyConfigurationName("dev.gradleplugins:gradle-api:${variant.gradleApiVersion}")
if (this@createGradlePluginVariant.name != "kotlin-gradle-plugin-api" &&
this@createGradlePluginVariant.name != "android-test-fixes"
) {
variantSourceSet.apiConfigurationName(project(":kotlin-gradle-plugin-api")) {
capabilities {
requireCapability("org.jetbrains.kotlin:kotlin-gradle-plugin-api-${variant.sourceSetName}")
}
}
}
}
return variantSourceSet
}
/**
* All additional configuration attributes in plugin variant should be the same as in the 'main' variant.
* Otherwise, Gradle <7.0 will fail to select plugin variant.
*/
private fun Project.commonVariantAttributes(): Action<Configuration> = Action<Configuration> {
attributes {
attribute(
TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE,
objects.named(TargetJvmEnvironment.STANDARD_JVM)
)
attribute(
Attribute.of(KotlinPlatformTypeAttribute.uniqueName, String::class.java),
KotlinPlatformTypeAttribute.JVM
)
}
}
fun Project.configureKotlinCompileTasksGradleCompatibility() {
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions.languageVersion = "1.4"
@@ -136,7 +435,8 @@ fun Project.configureKotlinCompileTasksGradleCompatibility() {
// Will allow combining outputs of multiple SourceSets
fun Project.publishShadowedJar(
sourceSet: SourceSet
sourceSet: SourceSet,
commonSourceSet: SourceSet
) {
val jarTask = tasks.named<Jar>(sourceSet.jarTaskName)
@@ -149,6 +449,7 @@ fun Project.publishShadowedJar(
)
addEmbeddedRuntime()
from(sourceSet.output)
from(commonSourceSet.output)
// When Gradle traverses the inputs, reject the shaded compiler JAR,
// which leads to the content of that JAR being excluded as well:
@@ -23,9 +23,6 @@ configure<PluginBundleExtension> {
tags = listOf("kotlin")
}
configureGradlePluginCommonSettings()
publishShadowedJar(sourceSets[SourceSet.MAIN_SOURCE_SET_NAME])
publishing {
publications {
withType<MavenPublication>().configureEach {
@@ -39,3 +36,14 @@ publishing {
}
}
}
val commonSourceSet = createGradleCommonSourceSet()
reconfigureMainSourcesSetForGradlePlugin(commonSourceSet)
publishShadowedJar(sourceSets[SourceSet.MAIN_SOURCE_SET_NAME], commonSourceSet)
// Used for Gradle 7.0+ versions
val gradle70SourceSet = createGradlePluginVariant(
GradlePluginVariant.GRADLE_70,
commonSourceSet = commonSourceSet
)
publishShadowedJar(gradle70SourceSet, commonSourceSet)
@@ -16,12 +16,21 @@ configureCommonPublicationSettingsForGradle()
configureKotlinCompileTasksGradleCompatibility()
extensions.extraProperties["kotlin.stdlib.default.dependency"] = "false"
configureGradlePluginCommonSettings()
val commonSourceSet = createGradleCommonSourceSet()
reconfigureMainSourcesSetForGradlePlugin(commonSourceSet)
// Used for Gradle 7.0+ versions
createGradlePluginVariant(
GradlePluginVariant.GRADLE_70,
commonSourceSet = commonSourceSet,
isGradlePlugin = false
)
publishing {
publications {
register<MavenPublication>(DEFAULT_MAIN_PUBLICATION_NAME) {
from(components["java"])
suppressAllPomMetadataWarnings() // Don't warn about additional published variants
}
}
}
+6
View File
@@ -3058,6 +3058,12 @@
<sha256 value="e5a3ac109ba1f12c534fd9ba730146011e18209ad1dd6398308cf75d841d3aab" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="dev.gradleplugins" name="gradle-api" version="7.0">
<artifact name="gradle-api-7.0.jar">
<md5 value="f58bcae3c212bd47161c97b2b330c497" origin="Generated by Gradle"/>
<sha256 value="0278f7da604d945ac53c222a937f08e6ea24834c10749a08e5fc12092595b5ad" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="dev.gradleplugins" name="gradle-api" version="7.1">
<artifact name="gradle-api-7.1.jar">
<md5 value="f76bd8fc83c4d405ea5c511465fb8695" origin="Generated by Gradle"/>