Resolve java-runtime everywhere

Gradle synthesises classified dependencies as java-runtime and now we
support these in lenient resolution

^KT-81467
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/UklibConsumptionSetupAction.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/UklibConsumptionSetupAction.kt
index 61048af..d0f8d4b 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/UklibConsumptionSetupAction.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/UklibConsumptionSetupAction.kt
@@ -348,6 +348,10 @@
              */
             JAVA_API,
             /**
+             * Classified JVM POM dependencies are synthesized as "java-runtime": KT-81467
+             */
+            JAVA_RUNTIME,
+            /**
              * Fallback to metadata variant to inherit dependencies for lenient interlibrary dependencies. Platform configurations
              * throw away metadata jars in [ThrowAwayMetadataJarsTransform]. GMT now always resolves and special-handles the case
              * when platform configurations resolved into metadata jar.
@@ -423,6 +427,10 @@
                      * Compatibility with all the Maven POM-only and Gradle JVM producers for dependency inheritance
                      */
                     JAVA_API,
+                    /**
+                     * Classified JVM POM dependencies are synthesized as "java-runtime": KT-81467
+                     */
+                    JAVA_RUNTIME,
                     KOTLIN_UKLIB_FALLBACK_VARIANT,
                 ),
             )[consumerUsage]?.contains(producerUsage) == true
diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/ResolutionTestingAttributes.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/ResolutionTestingAttributes.kt
index 886093f..967e187 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/ResolutionTestingAttributes.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/ResolutionTestingAttributes.kt
@@ -56,6 +56,10 @@
     "org.gradle.libraryelements" to "jar",
     "org.gradle.usage" to "java-api",
 )
+val jvmRuntimeClassifiedAttributes = mapOf(
+    "org.gradle.libraryelements" to "jar",
+    "org.gradle.usage" to "java-runtime",
+)
 
 val kmpJvmRuntimeVariantAttributes = mapOf(
     "org.gradle.category" to "library",
diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibResolutionWithMockComponents.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibResolutionWithMockComponents.kt
index 7c617a1..65332ae 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibResolutionWithMockComponents.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibResolutionWithMockComponents.kt
@@ -27,6 +27,7 @@
 import org.jetbrains.kotlin.gradle.testing.runtimeResolution
 import org.jetbrains.kotlin.gradle.unitTests.uklibs.GradleMetadataComponent.MockVariantType
 import org.jetbrains.kotlin.gradle.unitTests.uklibs.GradleMetadataComponent.Variant
+import org.jetbrains.kotlin.gradle.unitTests.uklibs.MavenComponent.MockArtifactType
 import org.jetbrains.kotlin.gradle.util.*
 import org.jetbrains.kotlin.incremental.createDirectory
 import org.junit.Rule
@@ -780,6 +781,87 @@
     }
 
     @Test
+    fun `uklib resolution - all configurations can resolve classified POM dependencies - KT-81467`() {
+        val repo = generateMockRepository(
+            tmpDir,
+            mavenComponents = listOf(
+                directMavenComponent(
+                    mocks = listOf(
+                        MockArtifactType.EmptyJar(),
+                        MockArtifactType.EmptyJar(classifier = "foo"),
+                    )
+                )
+            )
+        )
+
+        val consumer = uklibConsumer {
+            repositories.maven(repo)
+            kotlin {
+                iosArm64()
+                iosX64()
+                jvm()
+                js()
+                sourceSets.commonMain.dependencies { implementation("foo:direct:1.0:foo") }
+            }
+        }
+
+        listOf(
+            consumer.multiplatformExtension.iosArm64(),
+            consumer.multiplatformExtension.jvm(),
+            consumer.multiplatformExtension.js(),
+        ).forEach {
+            assertEquals(
+                mapOf<String, ResolvedComponentWithArtifacts>(
+                    "foo:direct:1.0" to ResolvedComponentWithArtifacts(
+                        configuration = "compile",
+                        artifacts = mutableListOf(
+                            jvmRuntimeClassifiedAttributes + jarArtifact,
+                        )
+                    )
+                ).prettyPrinted,
+                it.compilationResolution().prettyPrinted,
+                message = it.name
+            )
+        }
+
+        listOf(
+            consumer.multiplatformExtension.sourceSets.iosMain.get().internal.resolvableMetadataConfiguration,
+            consumer.multiplatformExtension.sourceSets.commonMain.get().internal.resolvableMetadataConfiguration,
+        ).forEach {
+            assertEquals(
+                mapOf<String, ResolvedComponentWithArtifacts>(
+                    "foo:direct:1.0" to ResolvedComponentWithArtifacts(
+                        configuration = "compile",
+                        artifacts = mutableListOf(
+                            jvmRuntimeClassifiedAttributes + jarArtifact,
+                        )
+                    )
+                ).prettyPrinted,
+                it.resolveProjectDependencyComponentsWithArtifacts().prettyPrinted,
+                message = it.name,
+            )
+        }
+
+        listOf(
+            consumer.multiplatformExtension.jvm(),
+            consumer.multiplatformExtension.js(),
+        ).forEach {
+            assertEquals(
+                mapOf<String, ResolvedComponentWithArtifacts>(
+                    "foo:direct:1.0" to ResolvedComponentWithArtifacts(
+                        configuration = "runtime",
+                        artifacts = mutableListOf(
+                            jvmRuntimeClassifiedAttributes + jarArtifact,
+                        )
+                    )
+                ).prettyPrinted,
+                it.runtimeResolution().prettyPrinted,
+                message = it.name,
+            )
+        }
+    }
+
+    @Test
     fun `uklib resolution - resolution with annotations`() {
         val consumer = uklibConsumer {
             repositories.mavenCentral()
@@ -1542,11 +1624,15 @@
         version = "1.0",
     )
 
-    private fun directMavenComponent(packaging: String? = null) = MavenComponent(
+    private fun directMavenComponent(
+        packaging: String? = null,
+        mocks: List<MockArtifactType> = listOf(MockArtifactType.EmptyJar())
+    ) = MavenComponent(
         directGradleComponent.group, directGradleComponent.module, directGradleComponent.version,
         packaging = packaging,
         dependencies = listOf(),
         true,
+        mocks = mocks,
     )
 
     private val uklibMock = GradleMetadataComponent.MockVariantFile(
@@ -1727,4 +1813,4 @@
         files = listOf(kmpJvmMock),
         dependencies = listOf()
     )
-}
\ No newline at end of file
+}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/generateMockRepository.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/generateMockRepository.kt
index 61f12cb..e093d9c 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/generateMockRepository.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/generateMockRepository.kt
@@ -121,6 +121,7 @@
     val packaging: String?,
     val dependencies: List<Dependency>,
     val gradleMetadataMarker: Boolean,
+    val mocks: List<MockArtifactType> = listOf(MockArtifactType.EmptyJar()),
 ) {
     class Dependency(
         val groupId: String?,
@@ -128,6 +129,12 @@
         val version: String?,
         val scope: String?,
     )
+
+    sealed class MockArtifactType(
+        val classifier: String?
+    ) {
+        class EmptyJar(classifier: String? = null) : MockArtifactType(classifier)
+    }
 }
 
 fun generateMockRepository(
@@ -204,10 +211,17 @@
         componentRoot.resolve("${mavenComponent.artifactId}-${mavenComponent.version}.pom").writeText(
             generatePom(mavenComponent)
         )
-        componentRoot.resolve("${mavenComponent.artifactId}-${mavenComponent.version}.jar").also {
-            // Avoid overwriting Gradle variant
-            if (!it.exists()) {
-                ZipOutputStream(FileOutputStream(it)).use {}
+        mavenComponent.mocks.forEach { mock ->
+            val coordinate = listOfNotNull(
+                mavenComponent.artifactId,
+                mavenComponent.version,
+                mock.classifier
+            ).joinToString("-")
+            componentRoot.resolve("${coordinate}.jar").also {
+                // Avoid overwriting Gradle variant
+                if (!it.exists()) {
+                    ZipOutputStream(FileOutputStream(it)).use {}
+                }
             }
         }
     }