diff --git a/build.gradle.kts b/build.gradle.kts index bdd07982832..2973a97930e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -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 by extra diff --git a/buildSrc/src/main/kotlin/GradleCommon.kt b/buildSrc/src/main/kotlin/GradleCommon.kt index 52f80c10acf..1c1cf17d6f1 100644 --- a/buildSrc/src/main/kotlin/GradleCommon.kt +++ b/buildSrc/src/main/kotlin/GradleCommon.kt @@ -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().configureEach { + this@createGradleCommonSourceSet.extensions.configure { + 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().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().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().configureEach { if (name == jarTaskName) { @@ -96,7 +261,7 @@ fun Project.configureGradlePluginCommonSettings() { } plugins.withType().configureEach { - this@configureGradlePluginCommonSettings + this@reconfigureMainSourcesSetForGradlePlugin .extensions .configure { withSourcesJar() @@ -111,7 +276,17 @@ fun Project.configureGradlePluginCommonSettings() { } plugins.withId("org.jetbrains.dokka") { - val dokkaTask = tasks.named("dokkaJavadoc") + val dokkaTask = tasks.named("dokkaJavadoc") { + dokkaSourceSets { + named(commonSourceSet.name) { + suppress.set(false) + } + + named("main") { + dependsOn(commonSourceSet) + } + } + } tasks.withType().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().configureEach { + extensions.configure { + 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(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("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(variantSourceSet.javadocJarTaskName) { + from(dokkaTask.flatMap { it.outputDirectory }) + } + } + } + + plugins.withId("java-gradle-plugin") { + tasks.named(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 = Action { + 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().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(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: diff --git a/buildSrc/src/main/kotlin/gradle-plugin-common-configuration.gradle.kts b/buildSrc/src/main/kotlin/gradle-plugin-common-configuration.gradle.kts index 9c488453b9d..a69caa617b6 100644 --- a/buildSrc/src/main/kotlin/gradle-plugin-common-configuration.gradle.kts +++ b/buildSrc/src/main/kotlin/gradle-plugin-common-configuration.gradle.kts @@ -23,9 +23,6 @@ configure { tags = listOf("kotlin") } -configureGradlePluginCommonSettings() -publishShadowedJar(sourceSets[SourceSet.MAIN_SOURCE_SET_NAME]) - publishing { publications { withType().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) diff --git a/buildSrc/src/main/kotlin/gradle-plugin-dependency-configuration.gradle.kts b/buildSrc/src/main/kotlin/gradle-plugin-dependency-configuration.gradle.kts index c231583fcde..dbe89bc329b 100644 --- a/buildSrc/src/main/kotlin/gradle-plugin-dependency-configuration.gradle.kts +++ b/buildSrc/src/main/kotlin/gradle-plugin-dependency-configuration.gradle.kts @@ -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(DEFAULT_MAIN_PUBLICATION_NAME) { from(components["java"]) + suppressAllPomMetadataWarnings() // Don't warn about additional published variants } } } diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 3cc2837fd99..a09f3a2ae32 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -3058,6 +3058,12 @@ + + + + + +