JEWEL-1374 declare Icons API modules as dependencies in published Jewel POMs

Jewel Standalone consumers hit `NoClassDefFoundError: com/intellij/platform/icons/IconManager`
at IntUiTheme startup because the generated POMs did not declare the Icons API modules
(`com.jetbrains.intellij.platform:icons-api` / `-api-rendering` / `-impl`), forcing consumers
to wire them by hand.

The POM generator's `patchDependencies` had no branch for the `com.jetbrains.intellij.platform`
groupId, so the icons dependencies fell into the implicit `else` and were silently dropped.
Emit them as `compile` dependencies instead: the icons-api types are part of Jewel's public API
(e.g. `Icon(...)` and the `iconKey(...)` DSL in jewel-ui), so `compile` is required for downstream
compilation and also mirrors the Gradle `api(project(":jb-icons-*"))` wiring.

Because `patchDependencies` receives a module's direct dependencies, this naturally scopes the
change to `jewel-ui` (icons-api, icons-api-rendering, icons-impl) and `jewel-int-ui-standalone`
(icons-api, icons-impl); other Jewel modules receive the icons transitively. The icons artifacts
themselves are already published to Maven Central by the earlier JEWEL-1354 work.

Add a regression test in MavenArtifactsBuilderTest that drives the public
`mavenArtifacts.patchDependencies` hook for `intellij.platform.jewel.ui` and asserts the icons
dependencies survive as `compile` with transitives; it fails without the generator fix.


(cherry picked from commit c5b8cdc2a7397a2eb23ad6aef4b1e5daaf3f6527)

IJ-MR-215743

GitOrigin-RevId: 84580c1f2537ab357c5cf7fea5e16bf8d6aaa867
This commit is contained in:
Nebojsa Vuksic
2026-08-07 15:34:23 +00:00
committed by intellij-monorepo-bot
parent fcd261bfba
commit b1b2b9a4e7
2 changed files with 49 additions and 0 deletions
@@ -157,6 +157,14 @@ internal object JewelMavenArtifacts {
add(dependency.withTransitiveDependencies(DependencyScope.COMPILE))
}
}
"com.jetbrains.intellij.platform" -> {
// Publish the Icons API modules (icons-api / icons-api-rendering / icons-impl) as compile
// dependencies, so consumers of the Jewel Standalone artifacts get IconManager on their
// classpath and can both boot IntUiTheme and compile against the public Icon/iconKey APIs.
if (coordinates.artifactId.startsWith("icons-")) {
add(dependency.withTransitiveDependencies(DependencyScope.COMPILE))
}
}
// else -> ignore the dependency, as it comes through transitively, usually from Compose.
@@ -5,7 +5,10 @@ import kotlinx.coroutines.runBlocking
import org.jetbrains.intellij.build.BuildPaths.Companion.COMMUNITY_ROOT
import org.jetbrains.intellij.build.BuildPaths.Companion.ULTIMATE_HOME
import org.jetbrains.intellij.build.impl.createBuildContext
import org.jetbrains.intellij.build.impl.maven.DependencyScope
import org.jetbrains.intellij.build.impl.maven.MavenArtifactDependency
import org.jetbrains.intellij.build.impl.maven.MavenArtifactsBuilder
import org.jetbrains.intellij.build.impl.maven.MavenCoordinates
import org.junit.Assert
import org.junit.Test
@@ -66,4 +69,42 @@ class MavenArtifactsBuilderTest {
Assert.assertTrue("Javadocs are not required for $moduleName", isJavadocJarRequired(module))
}
}
/**
* The Icons API modules are part of Jewel's public API surface (e.g. `Icon(...)` and the `iconKey(...)` DSL),
* so the published Jewel POMs must declare them as compile dependencies. Otherwise consumers of the standalone
* artifacts hit `NoClassDefFoundError: com/intellij/platform/icons/IconManager` at `IntUiTheme` startup.
* See JEWEL-1374.
*/
@Test
fun `jewel poms declare icons api dependencies`() {
val context = runBlocking {
createBuildContext(
projectHome = ULTIMATE_HOME,
productProperties = IdeaCommunityProperties(COMMUNITY_ROOT.communityRoot),
setupTracer = false,
)
}
val jewelUi = context.outputProvider.findRequiredModule("intellij.platform.jewel.ui")
val iconsDependencies = listOf("icons-api", "icons-api-rendering", "icons-impl").map { artifactId ->
MavenArtifactDependency(
coordinates = MavenCoordinates("com.jetbrains.intellij.platform", artifactId, "SNAPSHOT"),
includeTransitiveDeps = false,
excludedDependencies = emptyList(),
scope = null,
)
}
val patched = context.productProperties.mavenArtifacts.patchDependencies(jewelUi, iconsDependencies)
Assert.assertEquals(
"The Icons API dependencies must be kept in the jewel-ui POM",
iconsDependencies.map { it.coordinates.artifactId },
patched.map { it.coordinates.artifactId },
)
for (dependency in patched) {
Assert.assertEquals("${dependency.coordinates} must be a compile dependency", DependencyScope.COMPILE, dependency.scope)
Assert.assertTrue("${dependency.coordinates} must include transitive dependencies", dependency.includeTransitiveDeps)
}
}
}