Skip to content

Commit

Permalink
Fixed #1799 by creating a separate intellijPlatformComposedJarApi (ex…
Browse files Browse the repository at this point in the history
…tends api & compileOnlyApi) configuration with JAVA_API usage attribute value. Also replaced java plugin by java-library plugin, because it is a more proper plugin for IntelliJ plugin projects (they are libraries).
  • Loading branch information
AlexanderBartash committed Oct 21, 2024
1 parent f59b014 commit 6e65346
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
- Fixed issue #1778 by removing a hash of the absolute artifact path appended to the end of the version string. That hash made artifact version different on different PCs and also breaks Gradle dependency locking.
- Add the missing `org.jetbrains.kotlin.platform.type=jvm` attribute to the `intellijPlatformRuntimeClasspath` configuration manually as it's not inherited from the `runtimeClasspath`.
- Fixed `Could not generate a decorated class for type PluginArtifactRepository.` when creating a custom plugin repository.
- #1799: Gradle's api & compileOnlyApi configurations created by its java-library plugin do not work, and transitive implementation scope dependencies get exposed, when this plugin is used.

## [2.1.0]

Expand Down
4 changes: 4 additions & 0 deletions api/IntelliJPlatformGradlePlugin.api
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public final class org/jetbrains/intellij/platform/gradle/Constants$Configuratio
public static final field INTELLIJ_PLATFORM_BUNDLED_PLUGINS Ljava/lang/String;
public static final field INTELLIJ_PLATFORM_CLASSPATH Ljava/lang/String;
public static final field INTELLIJ_PLATFORM_COMPOSED_JAR Ljava/lang/String;
public static final field INTELLIJ_PLATFORM_COMPOSED_JAR_API Ljava/lang/String;
public static final field INTELLIJ_PLATFORM_DEPENDENCIES Ljava/lang/String;
public static final field INTELLIJ_PLATFORM_DEPENDENCY Ljava/lang/String;
public static final field INTELLIJ_PLATFORM_DEPENDENCY_ARCHIVE Ljava/lang/String;
Expand Down Expand Up @@ -82,8 +83,11 @@ public final class org/jetbrains/intellij/platform/gradle/Constants$Configuratio
}

public final class org/jetbrains/intellij/platform/gradle/Constants$Configurations$External {
public static final field API Ljava/lang/String;
public static final field API_ELEMENTS Ljava/lang/String;
public static final field COMPILE_CLASSPATH Ljava/lang/String;
public static final field COMPILE_ONLY Ljava/lang/String;
public static final field COMPILE_ONLY_API Ljava/lang/String;
public static final field IMPLEMENTATION Ljava/lang/String;
public static final field INSTANCE Lorg/jetbrains/intellij/platform/gradle/Constants$Configurations$External;
public static final field RUNTIME_CLASSPATH Ljava/lang/String;
Expand Down
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ ossrhUsername=
ossrhPassword=

gradleVersion=8.10.2
org.gradle.jvmargs = -Xmx4G

org.gradle.caching=true
#org.gradle.parallel=true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,13 @@ object Constants {
const val INTELLIJ_PLATFORM = "intellijPlatform"
}

/**
* See:
* - [Variant-aware sharing of artifacts between projects](https://docs.gradle.org/current/userguide/cross_project_publications.html#sec:variant-aware-sharing)
*/
object Configurations {
const val INTELLIJ_PLATFORM_COMPOSED_JAR = "intellijPlatformComposedJar"
const val INTELLIJ_PLATFORM_COMPOSED_JAR_API = "intellijPlatformComposedJarApi"
const val INTELLIJ_PLATFORM_DEPENDENCY_ARCHIVE = "intellijPlatformDependencyArchive"
const val INTELLIJ_PLATFORM_DISTRIBUTION = "intellijPlatformDistribution"
const val INTELLIJ_PLATFORM_LOCAL = "intellijPlatformLocal"
Expand Down Expand Up @@ -117,11 +122,19 @@ object Constants {
const val MARKETPLACE_GROUP = "com.jetbrains.plugins"
}

/**
* See:
* - [The Java Library plugin configurations](https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_configurations_graph)
* - [The Java plugin configurations](https://docs.gradle.org/current/userguide/java_plugin.html#resolvable_configurations)
*/
object External {
const val COMPILE_CLASSPATH = JvmConstants.COMPILE_CLASSPATH_CONFIGURATION_NAME
const val COMPILE_ONLY = JvmConstants.COMPILE_ONLY_CONFIGURATION_NAME
const val COMPILE_ONLY_API = JvmConstants.COMPILE_ONLY_API_CONFIGURATION_NAME
const val API = JvmConstants.API_CONFIGURATION_NAME
const val IMPLEMENTATION = JvmConstants.IMPLEMENTATION_CONFIGURATION_NAME
const val RUNTIME_CLASSPATH = JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME
const val API_ELEMENTS = JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME
const val RUNTIME_ELEMENTS = JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME
const val RUNTIME_ONLY = JavaPlugin.RUNTIME_ONLY_CONFIGURATION_NAME
const val TEST_COMPILE_CLASSPATH = JvmConstants.TEST_COMPILE_CLASSPATH_CONFIGURATION_NAME
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ import org.gradle.api.attributes.CompatibilityCheckDetails
import org.gradle.api.attributes.LibraryElements
import org.jetbrains.intellij.platform.gradle.Constants.Configurations.Attributes

/**
* See:
* - [Attribute Matching](https://docs.gradle.org/current/userguide/variant_attributes.html#sec:attribute_matching)
* - [Variant-aware sharing of artifacts between projects](https://docs.gradle.org/current/userguide/cross_project_publications.html#sec:variant-aware-sharing)
*/
abstract class ComposedJarRule : AttributeCompatibilityRule<LibraryElements> {

override fun execute(details: CompatibilityCheckDetails<LibraryElements>) = details.run {
if (consumerValue?.name == Attributes.COMPOSED_JAR_NAME && producerValue?.name == "jar") {
if (consumerValue?.name == Attributes.COMPOSED_JAR_NAME && producerValue?.name == LibraryElements.JAR) {
compatible()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ import org.gradle.api.attributes.CompatibilityCheckDetails
import org.gradle.api.attributes.LibraryElements
import org.jetbrains.intellij.platform.gradle.Constants.Configurations.Attributes

/**
* See:
* - [Attribute Matching](https://docs.gradle.org/current/userguide/variant_attributes.html#sec:attribute_matching)
* - [Variant-aware sharing of artifacts between projects](https://docs.gradle.org/current/userguide/cross_project_publications.html#sec:variant-aware-sharing)
*/
abstract class DistributionRule : AttributeCompatibilityRule<LibraryElements> {

override fun execute(details: CompatibilityCheckDetails<LibraryElements>) = details.run {
if (consumerValue?.name == Attributes.DISTRIBUTION_NAME && producerValue?.name == "jar") {
if (consumerValue?.name == Attributes.DISTRIBUTION_NAME && producerValue?.name == LibraryElements.JAR) {
compatible()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ package org.jetbrains.intellij.platform.gradle.plugins.project
import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.plugins.JavaLibraryPlugin
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.get
import org.gradle.plugins.ide.idea.IdeaPlugin
Expand Down Expand Up @@ -43,7 +43,10 @@ abstract class IntelliJPlatformBasePlugin : Plugin<Project> {
checkGradleVersion()

with(project.plugins) {
apply(JavaPlugin::class)
// https://docs.gradle.org/current/userguide/java_plugin.html
// https://docs.gradle.org/current/userguide/java_library_plugin.html
apply(JavaLibraryPlugin::class)
// https://docs.gradle.org/current/userguide/idea_plugin.html
apply(IdeaPlugin::class)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package org.jetbrains.intellij.platform.gradle.plugins.project
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.attributes.AttributeContainer
import org.gradle.api.attributes.Bundling
import org.gradle.api.attributes.Category
import org.gradle.api.attributes.LibraryElements
Expand Down Expand Up @@ -38,18 +39,59 @@ abstract class IntelliJPlatformModulePlugin : Plugin<Project> {
apply(IntelliJPlatformBasePlugin::class)
}

// To understand what is going on below read & watch this:
// https://youtu.be/2gPJD0mAres?t=461
// https://www.youtube.com/watch?v=8z5KFCLZDd0
// https://docs.gradle.org/current/userguide/variant_attributes.html#sec:standard_attributes
// https://docs.gradle.org/current/userguide/cross_project_publications.html#sec:variant-aware-sharing
with(project.configurations) configurations@{
fun Configuration.applyVariantAttributes() {
fun Configuration.applyVariantCommonAttributes(customAction: AttributeContainer.() -> Unit = {}) {
attributes {
attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling.EXTERNAL))
attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY))

// https://github.com/JetBrains/intellij-platform-gradle-plugin/issues/1772
// https://docs.gradle.org/current/userguide/cross_project_publications.html#targeting-different-platforms
// > By default, the org.gradle.jvm.version is set to the value of the release property
// > (or as fallback to the targetCompatibility value) of the main compilation task of the source set.
attributeProvider(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, project.provider {
project.the<JavaPluginExtension>().targetCompatibility.majorVersion.toInt()
})
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_RUNTIME))

attributes.attribute(Attributes.jvmEnvironment, "standard-jvm")
attributes.attribute(Attributes.kotlinJPlatformType, "jvm")

customAction()
}
}

create(
name = Configurations.INTELLIJ_PLATFORM_COMPOSED_JAR_API,
description = "IntelliJ Platform final composed Jar archive Api",
) {
// true & true is deprecated.
// https://docs.gradle.org/current/userguide/declaring_dependencies_adv.html#sec:resolvable-consumable-configs
// > For backwards compatibility, both flags have a default value of true, but as a plugin author,
// you should always determine the right values for those flags, or you might accidentally introduce
// resolution errors.
isCanBeConsumed = true
isCanBeResolved = false

applyVariantCommonAttributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_API))
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(Attributes.COMPOSED_JAR_NAME))
}

// A separate consumable _API configuration is necessary so that we can register a separate outgoing variant
// with `attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_API))` so that custom
// configurations api & compileOnlyApi created by `java-library` plugin can actually work.
// https://docs.gradle.org/current/userguide/java_library_plugin.html
// We cannot extend here from Configurations.External.COMPILE_ONLY_API.API_ELEMENTS because then
// we will inherit its -base.jar registered by the java plugin by default, which we do not want.
extendsFrom(
this@configurations[Configurations.External.API],
this@configurations[Configurations.External.COMPILE_ONLY_API]
)
}

create(
Expand All @@ -59,8 +101,13 @@ abstract class IntelliJPlatformModulePlugin : Plugin<Project> {
isCanBeConsumed = true
isCanBeResolved = true

applyVariantAttributes()
applyVariantCommonAttributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_RUNTIME))
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(Attributes.COMPOSED_JAR_NAME))
}

// We cannot extend here from Configurations.External.COMPILE_ONLY_API.RUNTIME_ELEMENTS because then
// we will inherit its -base.jar registered by the java plugin by default, which we do not want.
extendsFrom(
this@configurations[Configurations.External.IMPLEMENTATION],
this@configurations[Configurations.External.RUNTIME_ONLY],
Expand All @@ -70,10 +117,17 @@ abstract class IntelliJPlatformModulePlugin : Plugin<Project> {
name = Configurations.INTELLIJ_PLATFORM_DISTRIBUTION,
description = "IntelliJ Platform distribution Zip archive",
) {
// true & true is deprecated.
// https://docs.gradle.org/current/userguide/declaring_dependencies_adv.html#sec:resolvable-consumable-configs
// > For backwards compatibility, both flags have a default value of true, but as a plugin author,
// you should always determine the right values for those flags, or you might accidentally introduce
// resolution errors.
isCanBeConsumed = true
isCanBeResolved = false

applyVariantAttributes()
applyVariantCommonAttributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_RUNTIME))
}
}

val intellijPlatformPluginModuleConfiguration = create(
Expand All @@ -85,9 +139,7 @@ abstract class IntelliJPlatformModulePlugin : Plugin<Project> {
extendsFrom(intellijPlatformPluginModuleConfiguration)
}


listOf(
Configurations.INTELLIJ_PLATFORM_COMPOSED_JAR,
Configurations.INTELLIJ_PLATFORM_TEST_CLASSPATH,
Configurations.INTELLIJ_PLATFORM_RUNTIME_CLASSPATH,
Configurations.External.COMPILE_CLASSPATH,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ import org.jetbrains.intellij.platform.gradle.utils.extensionProvider
* depending on if code instrumentation is enabled with [IntelliJPlatformExtension.instrumentCode].
*
* The final Jar is also combined with plugin modules marked using the [IntelliJPlatformDependenciesExtension.pluginModule] dependencies helper.
*
* To understand what is going on in this class read & watch this:
* - [1](https://youtu.be/2gPJD0mAres?t=461)
* - [2](https://www.youtube.com/watch?v=8z5KFCLZDd0)
* - [3](https://docs.gradle.org/current/userguide/variant_attributes.html#sec:standard_attributes)
* - [4](https://docs.gradle.org/current/userguide/cross_project_publications.html#sec:variant-aware-sharing)
*/
@CacheableTask
abstract class ComposedJarTask : Jar() {
Expand All @@ -41,6 +47,7 @@ abstract class ComposedJarTask : Jar() {
val instrumentedJarTaskProvider = project.tasks.named<Jar>(Tasks.INSTRUMENTED_JAR)
val intellijPlatformPluginModuleConfiguration = project.configurations[Configurations.INTELLIJ_PLATFORM_PLUGIN_MODULE]
val intellijPlatformComposedJarConfiguration = project.configurations[Configurations.INTELLIJ_PLATFORM_COMPOSED_JAR]
val intellijPlatformComposedJarApiConfiguration = project.configurations[Configurations.INTELLIJ_PLATFORM_COMPOSED_JAR_API]

val sourceTaskProvider = project.extensionProvider.flatMap {
it.instrumentCode.flatMap { value ->
Expand All @@ -64,7 +71,8 @@ abstract class ComposedJarTask : Jar() {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
JarCompanion.applyPluginManifest(this)

project.artifacts.add(intellijPlatformComposedJarConfiguration.name, this)
intellijPlatformComposedJarConfiguration.outgoing.artifact(this)
intellijPlatformComposedJarApiConfiguration.outgoing.artifact(this)

softwareComponentFactory.adhoc(Components.INTELLIJ_PLATFORM).apply {
project.components.add(this)
Expand Down

0 comments on commit 6e65346

Please sign in to comment.